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.13 2000/08/21 14:21:21 priikone
24 * Fixed channel joining and channel message sending inside a
25 * SILC cell. Added silc_server_send_remove_channel_user and
26 * silc_server_remove_channel_user functions.
28 * Revision 1.12 2000/07/26 07:05:11 priikone
29 * Fixed the server to server (server to router actually) connections
30 * and made the private message work inside a cell. Added functin
31 * silc_server_replace_id.
33 * Revision 1.11 2000/07/19 07:08:09 priikone
34 * Added version detection support to SKE.
36 * Revision 1.10 2000/07/17 11:47:30 priikone
37 * Added command lagging support. Added idle counting support.
39 * Revision 1.9 2000/07/12 05:59:41 priikone
40 * Major rewrite of ID Cache system. Support added for the new
41 * ID cache system. Major rewrite of ID List stuff on server. All
42 * SilcXXXList's are now called SilcXXXEntry's and they are pointers
43 * by default. A lot rewritten ID list functions.
45 * Revision 1.8 2000/07/10 05:42:59 priikone
46 * Removed command packet processing from server.c and added it to
48 * Implemented INFO command. Added support for testing that
49 * connections are registered before executing commands.
51 * Revision 1.7 2000/07/07 06:55:24 priikone
52 * Do not allow client to join twice on same channel.
54 * Revision 1.6 2000/07/06 10:20:59 priikone
55 * Cipher name in joining is not mandatory, removed check.
57 * Revision 1.5 2000/07/06 07:16:43 priikone
58 * Fixed a wrong way of sending command replies. The fixed way
59 * does comply with the protocol.
61 * Revision 1.4 2000/07/05 06:13:38 priikone
62 * Added PING, INVITE and NAMES command.
64 * Revision 1.3 2000/07/03 05:52:22 priikone
65 * Implemented LEAVE command.
67 * Revision 1.2 2000/06/28 05:06:38 priikone
68 * Shorter timeout for channel joining notify.
70 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
71 * Imported from internal CVS/Added Log headers.
76 #include "serverincludes.h"
77 #include "server_internal.h"
79 static int silc_server_is_registered(SilcServer server,
80 SilcSocketConnection sock,
81 SilcServerCommandContext cmd,
84 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
86 SilcCommandStatus status);
88 silc_server_command_send_status_data(SilcServerCommandContext cmd,
90 SilcCommandStatus status,
91 unsigned int arg_type,
93 unsigned int arg_len);
94 static void silc_server_command_free(SilcServerCommandContext cmd);
96 /* Server command list. */
97 SilcServerCommand silc_command_list[] =
99 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
100 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
101 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
102 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
103 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
104 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
105 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
106 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
107 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
108 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
109 SILC_SERVER_CMD(connect, CONNECT,
110 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
111 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
112 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
113 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
114 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
115 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
116 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
117 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
118 SILC_SERVER_CMD(restart, RESTART,
119 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
120 SILC_SERVER_CMD(close, CLOSE,
121 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
122 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
123 SILC_SERVER_CMD(silcoper, SILCOPER,
124 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
125 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
126 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
131 /* List of pending commands. */
132 SilcServerCommandPending *silc_command_pending = NULL;
134 /* Returns TRUE if the connection is registered. Unregistered connections
135 usually cannot send commands hence the check. */
137 static int silc_server_is_registered(SilcServer server,
138 SilcSocketConnection sock,
139 SilcServerCommandContext cmd,
143 case SILC_SOCKET_TYPE_CLIENT:
145 SilcClientEntry client = (SilcClientEntry)sock->user_data;
146 if (client->registered)
150 case SILC_SOCKET_TYPE_SERVER:
151 case SILC_SOCKET_TYPE_ROUTER:
153 SilcServerEntry serv = (SilcServerEntry)sock->user_data;
154 if (serv->registered)
162 silc_server_command_send_status_reply(cmd, command,
163 SILC_STATUS_ERR_NOT_REGISTERED);
164 silc_server_command_free(cmd);
168 /* Processes received command packet. */
170 void silc_server_command_process(SilcServer server,
171 SilcSocketConnection sock,
172 SilcPacketContext *packet)
174 SilcServerCommandContext ctx;
175 SilcServerCommand *cmd;
177 /* Check whether it is allowed for this connection to execute any
179 if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
181 SilcClientEntry client = (SilcClientEntry)sock->user_data;
186 /* Allow only one command executed in 2 seconds. */
187 curtime = time(NULL);
188 if (client->last_command && (curtime - client->last_command) < 2)
191 /* Update access time */
192 client->last_command = curtime;
195 /* Allocate command context. This must be free'd by the
196 command routine receiving it. */
197 ctx = silc_calloc(1, sizeof(*ctx));
198 ctx->server = server;
200 ctx->packet = packet; /* Save original packet */
202 /* Parse the command payload in the packet */
203 ctx->payload = silc_command_parse_payload(packet->buffer);
205 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
206 silc_buffer_free(packet->buffer);
211 /* Execute command. If this fails the packet is dropped. */
212 for (cmd = silc_command_list; cmd->cb; cmd++)
213 if (cmd->cmd == silc_command_get(ctx->payload)) {
215 if (!(cmd->flags & SILC_CF_REG)) {
220 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
227 SILC_LOG_ERROR(("Unknown command, packet dropped"));
233 silc_buffer_free(packet->buffer);
236 /* Add new pending command to the list of pending commands. Currently
237 pending commands are executed from command replies, thus we can
238 execute any command after receiving some specific command reply.
240 The argument `reply_cmd' is the command reply from where the callback
241 function is to be called, thus, it IS NOT the command to be executed. */
243 void silc_server_command_pending(SilcCommand reply_cmd,
244 SilcCommandCb callback,
247 SilcServerCommandPending *reply, *r;
249 reply = silc_calloc(1, sizeof(*reply));
250 reply->reply_cmd = reply_cmd;
251 reply->context = context;
252 reply->callback = callback;
254 if (silc_command_pending == NULL) {
255 silc_command_pending = reply;
259 for (r = silc_command_pending; r; r = r->next) {
260 if (r->next == NULL) {
267 /* Deletes pending command by reply command type. */
269 void silc_server_command_pending_del(SilcCommand reply_cmd)
271 SilcServerCommandPending *r, *tmp;
273 if (silc_command_pending) {
274 if (silc_command_pending->reply_cmd == reply_cmd) {
275 silc_free(silc_command_pending);
276 silc_command_pending = NULL;
280 for (r = silc_command_pending; r; r = r->next) {
281 if (r->next && r->next->reply_cmd == reply_cmd) {
283 r->next = r->next->next;
291 /* Free's the command context allocated before executing the command */
293 static void silc_server_command_free(SilcServerCommandContext cmd)
296 silc_command_free_payload(cmd->payload);
301 #define SILC_COMMAND_STATUS_DATA(x) \
304 /* Sends simple status message as command reply packet */
307 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
309 SilcCommandStatus status)
313 SILC_LOG_DEBUG(("Sending command status %d", status));
315 buffer = silc_command_encode_reply_payload_va(command, status, 0);
316 silc_server_packet_send(cmd->server, cmd->sock,
317 SILC_PACKET_COMMAND_REPLY, 0,
318 buffer->data, buffer->len, FALSE);
319 silc_buffer_free(buffer);
322 /* Sends command status reply with one extra argument. The argument
323 type must be sent as argument. */
326 silc_server_command_send_status_data(SilcServerCommandContext cmd,
328 SilcCommandStatus status,
329 unsigned int arg_type,
331 unsigned int arg_len)
335 SILC_LOG_DEBUG(("Sending command status %d", status));
337 buffer = silc_command_encode_reply_payload_va(command, status, 1,
338 arg_type, arg, arg_len);
339 silc_server_packet_send(cmd->server, cmd->sock,
340 SILC_PACKET_COMMAND_REPLY, 0,
341 buffer->data, buffer->len, FALSE);
342 silc_buffer_free(buffer);
345 /* Server side of command WHOIS. Processes user's query and sends found
346 results as command replies back to the client. */
348 SILC_SERVER_CMD_FUNC(whois)
350 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
351 SilcServer server = cmd->server;
352 char *tmp, *nick = NULL, *server_name = NULL;
353 unsigned int argc, count = 0, len;
354 SilcClientEntry entry;
356 unsigned char *id_string;
358 SILC_LOG_DEBUG(("Start"));
360 argc = silc_command_get_arg_num(cmd->payload);
362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
363 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
367 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
368 SILC_STATUS_ERR_TOO_MANY_PARAMS);
372 /* Get the nickname@server string and parse it. */
373 tmp = silc_command_get_first_arg(cmd->payload, NULL);
375 if (strchr(tmp, '@')) {
376 len = strcspn(tmp, "@");
377 nick = silc_calloc(len + 1, sizeof(char));
378 memcpy(nick, tmp, len);
379 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
380 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
385 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
386 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
390 /* Get the max count of reply messages allowed */
392 tmp = silc_command_get_next_arg(cmd->payload, NULL);
394 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
395 SILC_STATUS_ERR_TOO_MANY_PARAMS);
399 silc_free(server_name);
405 /* Then, make the query from our local client list */
406 entry = silc_idlist_find_client_by_nickname(server->local_list,
410 /* If we are normal server and are connected to a router we will
411 make global query from the router. */
412 if (server->server_type == SILC_SERVER && !server->standalone) {
417 /* If we are router then we will check our global list as well. */
418 if (server->server_type == SILC_ROUTER) {
420 silc_idlist_find_client_by_nickname(server->global_list,
423 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
424 SILC_STATUS_ERR_NO_SUCH_NICK,
425 3, tmp, strlen(tmp));
431 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
432 SILC_STATUS_ERR_NO_SUCH_NICK,
433 3, tmp, strlen(tmp));
438 /* XXX, works only for local server info */
440 /* Send WHOIS reply */
441 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
442 tmp = silc_command_get_first_arg(cmd->payload, NULL);
445 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
446 char nh[256], uh[256];
447 unsigned char idle[4];
448 SilcSocketConnection hsock;
450 memset(uh, 0, sizeof(uh));
451 memset(nh, 0, sizeof(nh));
453 strncat(nh, entry->nickname, strlen(entry->nickname));
455 len = entry->router ? strlen(entry->router->server_name) :
456 strlen(server->server_name);
457 strncat(nh, entry->router ? entry->router->server_name :
458 server->server_name, len);
460 strncat(uh, entry->username, strlen(entry->username));
462 hsock = (SilcSocketConnection)entry->connection;
463 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
464 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
466 SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
471 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
473 2, id_string, SILC_ID_CLIENT_LEN,
477 strlen(entry->userinfo),
481 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
483 2, id_string, SILC_ID_CLIENT_LEN,
491 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
493 2, id_string, SILC_ID_CLIENT_LEN,
495 strlen(entry->nickname),
496 4, tmp, strlen(tmp)); /* XXX */
498 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
499 0, packet->data, packet->len, FALSE);
501 silc_free(id_string);
502 silc_buffer_free(packet);
505 silc_server_command_free(cmd);
508 SILC_SERVER_CMD_FUNC(whowas)
512 SILC_SERVER_CMD_FUNC(identify)
514 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
515 SilcServer server = cmd->server;
516 char *tmp, *nick = NULL, *server_name = NULL;
517 unsigned int argc, count = 0, len;
518 SilcClientEntry entry;
520 unsigned char *id_string;
522 SILC_LOG_DEBUG(("Start"));
524 argc = silc_command_get_arg_num(cmd->payload);
526 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
527 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
531 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
532 SILC_STATUS_ERR_TOO_MANY_PARAMS);
536 /* Get the nickname@server string and parse it. */
537 tmp = silc_command_get_first_arg(cmd->payload, NULL);
539 if (strchr(tmp, '@')) {
540 len = strcspn(tmp, "@");
541 nick = silc_calloc(len + 1, sizeof(char));
542 memcpy(nick, tmp, len);
543 server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
544 memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
549 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
550 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
554 /* Get the max count of reply messages allowed */
556 tmp = silc_command_get_next_arg(cmd->payload, NULL);
558 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
559 SILC_STATUS_ERR_TOO_MANY_PARAMS);
566 entry = silc_idlist_find_client_by_nickname(server->local_list,
569 entry = silc_idlist_find_client_by_hash(server->global_list,
570 nick, server->md5hash);
572 /* If client was not found and if we are normal server and are connected
573 to a router we will make global query from the router. */
574 if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
576 SilcBuffer buffer = cmd->packet->buffer;
578 SILC_LOG_DEBUG(("Requesting identify from router"));
580 /* Send IDENTIFY command to our router */
581 silc_buffer_push(buffer, buffer->data - buffer->head);
582 silc_server_packet_forward(server, (SilcSocketConnection)
583 server->id_entry->router->connection,
584 buffer->data, buffer->len, TRUE);
588 /* If we are router we have checked our local list by nickname and our
589 global list by hash so far. It is possible that the client is still not
590 found and we'll check it from local list by hash. */
591 if (!entry && server->server_type == SILC_ROUTER)
592 entry = silc_idlist_find_client_by_hash(server->local_list,
593 nick, server->md5hash);
596 /* The client definitely does not exist */
597 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
598 SILC_STATUS_ERR_NO_SUCH_NICK,
599 3, tmp, strlen(tmp));
603 /* Send IDENTIFY reply */
604 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
605 tmp = silc_command_get_first_arg(cmd->payload, NULL);
606 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
610 3, nick, strlen(nick));
611 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
612 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
613 silc_server_packet_send_dest(server, cmd->sock,
614 SILC_PACKET_COMMAND_REPLY, 0,
615 id, cmd->packet->src_id_type,
616 packet->data, packet->len, FALSE);
619 silc_server_packet_send(server, cmd->sock,
620 SILC_PACKET_COMMAND_REPLY, 0,
621 packet->data, packet->len, FALSE);
624 silc_free(id_string);
625 silc_buffer_free(packet);
631 silc_free(server_name);
632 silc_server_command_free(cmd);
635 /* Checks string for bad characters and returns TRUE if they are found. */
637 static int silc_server_command_bad_chars(char *nick)
639 if (strchr(nick, '\\')) return TRUE;
640 if (strchr(nick, '\"')) return TRUE;
641 if (strchr(nick, '´')) return TRUE;
642 if (strchr(nick, '`')) return TRUE;
643 if (strchr(nick, '\'')) return TRUE;
644 if (strchr(nick, '*')) return TRUE;
645 if (strchr(nick, '/')) return TRUE;
646 if (strchr(nick, '@')) return TRUE;
651 /* Server side of command NICK. Sets nickname for user. Setting
652 nickname causes generation of a new client ID for the client. The
653 new client ID is sent to the client after changing the nickname. */
655 SILC_SERVER_CMD_FUNC(nick)
657 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
658 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
659 SilcServer server = cmd->server;
661 SilcClientID *new_id;
665 SILC_LOG_DEBUG(("Start"));
667 /* Check number of arguments */
668 if (silc_command_get_arg_num(cmd->payload) < 1) {
669 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
670 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
675 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
676 if (silc_server_command_bad_chars(nick) == TRUE) {
677 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
678 SILC_STATUS_ERR_BAD_NICKNAME);
682 /* Create new Client ID */
683 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
684 cmd->server->md5hash, nick,
687 /* Send notify about nickname change to our router. We send the new
688 ID and ask to replace it with the old one. */
689 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
690 silc_server_send_replace_id(server, server->id_entry->router->connection,
692 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
693 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
695 /* If we are router we have to distribute the new Client ID to all
697 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
698 silc_server_send_replace_id(server, server->id_entry->router->connection,
700 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
701 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
703 /* Remove old cache entry */
704 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
709 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
710 silc_free(id_entry->id);
713 /* Save the nickname as this client is our local client */
714 if (id_entry->nickname)
715 silc_free(id_entry->nickname);
717 id_entry->nickname = strdup(nick);
718 id_entry->id = new_id;
720 /* Update client cache */
721 silc_idcache_add(server->local_list->clients, id_entry->nickname,
722 SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
724 /* Send the new Client ID as reply command back to client */
725 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
726 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
730 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
731 0, packet->data, packet->len, FALSE);
733 silc_free(id_string);
734 silc_buffer_free(packet);
737 silc_server_command_free(cmd);
740 SILC_SERVER_CMD_FUNC(list)
744 SILC_SERVER_CMD_FUNC(topic)
748 /* Server side of INVITE command. Invites some client to join some channel. */
750 SILC_SERVER_CMD_FUNC(invite)
752 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
753 SilcServer server = cmd->server;
754 SilcSocketConnection sock = cmd->sock, dest_sock;
755 SilcClientEntry sender, dest;
756 SilcClientID *dest_id;
757 SilcChannelEntry channel;
758 SilcChannelID *channel_id;
759 unsigned int argc, len;
760 unsigned char *id_string;
762 /* Check number of arguments */
763 argc = silc_command_get_arg_num(cmd->payload);
765 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
766 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
770 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
771 SILC_STATUS_ERR_TOO_MANY_PARAMS);
775 /* Get destination ID */
776 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
778 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
779 SILC_STATUS_ERR_NO_CLIENT_ID);
782 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
785 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
787 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
788 SILC_STATUS_ERR_NO_CHANNEL_ID);
791 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
793 /* Check whether the channel exists */
794 channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
796 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
797 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
801 /* Check whether the sender of this command is on the channel. */
802 sender = (SilcClientEntry )sock->user_data;
803 if (!silc_server_client_on_channel(sender, channel)) {
804 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
805 SILC_STATUS_ERR_NOT_ON_CHANNEL);
809 /* Check whether the channel is invite-only channel. If yes then the
810 sender of this command must be at least channel operator. */
813 /* Find the connection data for the destination. If it is local we will
814 send it directly otherwise we will send it to router for routing. */
815 dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
817 dest_sock = (SilcSocketConnection)dest->connection;
819 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
821 /* Check whether the requested client is already on the channel. */
822 /* XXX if we are normal server we don't know about global clients on
823 the channel thus we must request it (NAMES command), check from
824 local cache as well. */
825 if (silc_server_client_on_channel(dest, channel)) {
826 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
827 SILC_STATUS_ERR_USER_ON_CHANNEL);
831 /* Send notify to the client that is invited to the channel */
832 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
833 "%s invites you to channel %s",
834 sender->nickname, channel->channel_name);
836 /* Send command reply */
837 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
841 silc_server_command_free(cmd);
844 /* Quits connection to client. This gets called if client won't
845 close the connection even when it has issued QUIT command. */
847 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
849 SilcServer server = (SilcServer)context;
850 SilcSocketConnection sock = server->sockets[fd];
852 /* Free all client specific data, such as client entry and entires
853 on channels this client may be on. */
854 silc_server_free_sock_user_data(server, sock);
856 /* Close the connection on our side */
857 silc_server_close_connection(server, sock);
860 /* Quits SILC session. This is the normal way to disconnect client. */
862 SILC_SERVER_CMD_FUNC(quit)
864 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
865 SilcServer server = cmd->server;
866 SilcSocketConnection sock = cmd->sock;
868 SILC_LOG_DEBUG(("Start"));
870 /* We quit the connection with little timeout */
871 silc_task_register(server->timeout_queue, sock->sock,
872 silc_server_command_quit_cb, server,
873 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
875 silc_server_command_free(cmd);
878 SILC_SERVER_CMD_FUNC(kill)
882 /* Server side of command INFO. This sends information about us to
883 the client. If client requested specific server we will send the
884 command to that server. */
886 SILC_SERVER_CMD_FUNC(info)
888 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
889 SilcServer server = cmd->server;
892 unsigned char *id_string;
893 char info_string[256], *dest_server;
895 argc = silc_command_get_arg_num(cmd->payload);
897 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
898 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
902 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
903 SILC_STATUS_ERR_TOO_MANY_PARAMS);
907 /* Get server name */
908 dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
910 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
911 SILC_STATUS_ERR_NO_SUCH_SERVER);
915 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
917 memset(info_string, 0, sizeof(info_string));
918 snprintf(info_string, sizeof(info_string),
919 "location: %s server: %s admin: %s <%s>",
920 server->config->admin_info->location,
921 server->config->admin_info->server_type,
922 server->config->admin_info->admin_name,
923 server->config->admin_info->admin_email);
925 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
928 silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
930 2, id_string, SILC_ID_SERVER_LEN,
932 strlen(info_string));
933 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
934 packet->data, packet->len, FALSE);
936 silc_free(id_string);
937 silc_buffer_free(packet);
939 /* Send this command to the requested server */
941 if (server->server_type == SILC_SERVER && !server->standalone) {
945 if (server->server_type == SILC_ROUTER) {
951 silc_server_command_free(cmd);
954 SILC_SERVER_CMD_FUNC(connect)
958 /* Server side of command PING. This just replies to the ping. */
960 SILC_SERVER_CMD_FUNC(ping)
962 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
963 SilcServer server = cmd->server;
966 unsigned char *id_string;
968 argc = silc_command_get_arg_num(cmd->payload);
970 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
971 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
975 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
976 SILC_STATUS_ERR_TOO_MANY_PARAMS);
981 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
983 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
984 SILC_STATUS_ERR_NO_SERVER_ID);
987 id = silc_id_str2id(id_string, SILC_ID_SERVER);
989 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
991 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
994 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
995 SILC_STATUS_ERR_NO_SUCH_SERVER);
1002 silc_server_command_free(cmd);
1005 SILC_SERVER_CMD_FUNC(oper)
1014 SilcChannelEntry channel;
1016 } JoinInternalContext;
1018 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1020 JoinInternalContext *ctx = (JoinInternalContext *)context;
1022 if (ctx->channel->key && ctx->channel->key_len) {
1023 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
1024 "%s (%s@%s) has joined channel %s",
1025 ctx->nickname, ctx->username,
1026 ctx->hostname, ctx->channel_name);
1029 silc_task_register(ctx->server->timeout_queue, fd,
1030 silc_server_command_join_notify, context,
1031 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1035 /* Assembles NAMES command and executes it. This is called when client
1036 joins to a channel and we wan't to send NAMES command reply to the
1039 void silc_server_command_send_names(SilcServer server,
1040 SilcSocketConnection sock,
1041 SilcChannelEntry channel)
1043 SilcServerCommandContext cmd;
1045 unsigned char *id_string;
1047 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1048 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1049 1, id_string, SILC_ID_CHANNEL_LEN);
1051 cmd = silc_calloc(1, sizeof(*cmd));
1052 cmd->payload = silc_command_parse_payload(buffer);
1053 cmd->server = server;
1055 cmd->pending = FALSE;
1057 silc_server_command_names((void *)cmd);
1058 silc_free(id_string);
1062 /* Server side of command JOIN. Joins client into requested channel. If
1063 the channel does not exist it will be created. */
1065 SILC_SERVER_CMD_FUNC(join)
1067 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1068 SilcServer server = cmd->server;
1069 SilcSocketConnection sock = cmd->sock;
1070 SilcBuffer buffer = cmd->packet->buffer;
1071 int argc, i, tmp_len;
1072 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1073 unsigned char *passphrase, mode[4];
1074 SilcChannelEntry channel;
1075 SilcServerID *router_id;
1077 SilcClientEntry client;
1079 SILC_LOG_DEBUG(("Start"));
1081 /* Check number of parameters */
1082 argc = silc_command_get_arg_num(cmd->payload);
1084 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1085 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1089 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1090 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1094 /* Get channel name */
1095 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1096 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1097 memcpy(channel_name, tmp, tmp_len);
1098 if (silc_server_command_bad_chars(tmp) == TRUE) {
1099 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1100 SILC_STATUS_ERR_BAD_CHANNEL);
1101 silc_free(channel_name);
1105 /* Get passphrase */
1106 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1108 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1109 memcpy(passphrase, tmp, tmp_len);
1112 /* Get cipher name */
1113 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1115 /* See if the channel exists */
1117 silc_idlist_find_channel_by_name(server->local_list, channel_name);
1119 /* Channel not found */
1121 /* If we are standalone server we don't have a router, we just create
1122 the channel by ourselves. */
1123 if (server->standalone) {
1124 router_id = server->id;
1125 channel = silc_server_new_channel(server, router_id,
1126 cipher, channel_name);
1133 /* No channel ID found, the channel does not exist on our server.
1134 We send JOIN command to our router which will handle the joining
1135 procedure (either creates the channel if it doesn't exist or
1136 joins the client to it) - if we are normal server. */
1137 if (server->server_type == SILC_SERVER) {
1139 /* Forward the original JOIN command to the router */
1140 silc_buffer_push(buffer, buffer->data - buffer->head);
1141 silc_server_packet_forward(server, (SilcSocketConnection)
1142 server->id_entry->router->connection,
1143 buffer->data, buffer->len, TRUE);
1145 /* Add the command to be pending. It will be re-executed after
1146 router has replied back to us. */
1147 cmd->pending = TRUE;
1148 silc_server_command_pending(SILC_COMMAND_JOIN,
1149 silc_server_command_join, context);
1154 /* If we are router and the channel does not exist we will check our
1155 global list for the channel. */
1156 if (!channel && server->server_type == SILC_ROUTER) {
1158 /* Notify all routers about the new channel in SILC network. */
1159 if (!server->standalone) {
1161 silc_server_send_new_id(server, server->id_entry->router->connection,
1163 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1171 /* If the JOIN request was forwarded to us we will make a bit slower
1172 query to get the client pointer. Otherwise, we get the client pointer
1174 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1175 client = (SilcClientEntry)sock->user_data;
1177 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1178 client = silc_idlist_find_client_by_id(server->local_list, id);
1186 /* Check whether the client already is on the channel */
1187 if (silc_server_client_on_channel(client, channel)) {
1188 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1189 SILC_STATUS_ERR_USER_ON_CHANNEL);
1190 silc_free(channel_name);
1194 /* Join the client to the channel */
1195 i = channel->user_list_count;
1196 channel->user_list = silc_realloc(channel->user_list,
1197 sizeof(*channel->user_list) * (i + 1));
1198 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1199 channel->user_list[i].client = client;
1200 channel->user_list_count++;
1202 /* Add the channel to client's channel list */
1203 i = client->channel_count;
1204 client->channel = silc_realloc(client->channel,
1205 sizeof(*client->channel) * (i + 1));
1206 client->channel[i] = channel;
1207 client->channel_count++;
1209 /* Notify router about new user on channel. If we are normal server
1210 we send it to our router, if we are router we send it to our
1212 if (!server->standalone) {
1216 /* Send command reply to the client. Client receives the Channe ID,
1217 channel mode and possibly other information in this reply packet. */
1218 if (!cmd->pending) {
1219 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1220 SILC_PUT32_MSB(channel->mode, mode);
1222 if (!channel->topic)
1224 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1227 strlen(channel_name),
1228 3, id_string, SILC_ID_CHANNEL_LEN,
1232 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1235 strlen(channel_name),
1236 3, id_string, SILC_ID_CHANNEL_LEN,
1239 strlen(channel->topic));
1241 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1242 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1243 silc_server_packet_send_dest(cmd->server, cmd->sock,
1244 SILC_PACKET_COMMAND_REPLY, 0,
1245 id, cmd->packet->src_id_type,
1246 packet->data, packet->len, FALSE);
1249 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1250 packet->data, packet->len, FALSE);
1252 silc_buffer_free(packet);
1255 /* Send channel key to the client. Client cannot start transmitting
1256 to the channel until we have sent the key. */
1257 if (!cmd->pending) {
1258 tmp_len = strlen(channel->channel_key->cipher->name);
1260 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1262 channel->channel_key->cipher->name,
1263 channel->key_len / 8, channel->key);
1265 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1266 packet->data, packet->len, FALSE);
1267 silc_buffer_free(packet);
1271 silc_free(id_string);
1273 /* Finally, send notify message to all clients on the channel about
1274 new user on the channel. */
1275 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1276 if (!cmd->pending) {
1277 silc_server_send_notify_to_channel(server, channel,
1278 "%s (%s@%s) has joined channel %s",
1279 client->nickname, client->username,
1280 sock->hostname ? sock->hostname :
1281 sock->ip, channel_name);
1283 /* This is pending command request. Send the notify after we have
1284 received the key for the channel from the router. */
1285 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1286 ctx->channel_name = channel_name;
1287 ctx->nickname = client->nickname;
1288 ctx->username = client->username;
1289 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1290 ctx->channel = channel;
1291 ctx->server = server;
1292 silc_task_register(server->timeout_queue, sock->sock,
1293 silc_server_command_join_notify, ctx,
1294 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1298 /* Send NAMES command reply to the joined channel so the user sees who
1299 is currently on the channel. */
1300 silc_server_command_send_names(server, sock, channel);
1303 silc_server_command_free(cmd);
1306 /* Server side of command MOTD. Sends servers current "message of the
1307 day" to the client. */
1309 SILC_SERVER_CMD_FUNC(motd)
1312 SILC_LOG_DEBUG(("Start"));
1316 SILC_SERVER_CMD_FUNC(umode)
1320 SILC_SERVER_CMD_FUNC(cmode)
1324 SILC_SERVER_CMD_FUNC(kick)
1328 SILC_SERVER_CMD_FUNC(restart)
1332 SILC_SERVER_CMD_FUNC(close)
1336 SILC_SERVER_CMD_FUNC(die)
1340 SILC_SERVER_CMD_FUNC(silcoper)
1344 /* Server side command of LEAVE. Removes client from a channel. */
1346 SILC_SERVER_CMD_FUNC(leave)
1348 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1349 SilcServer server = cmd->server;
1350 SilcSocketConnection sock = cmd->sock;
1351 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
1353 SilcChannelEntry channel;
1355 unsigned int i, argc, key_len;
1356 unsigned char *tmp, channel_key[32];
1358 SILC_LOG_DEBUG(("Start"));
1360 argc = silc_command_get_arg_num(cmd->payload);
1362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1363 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1367 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1368 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1372 /* Get Channel ID */
1373 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1375 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1376 SILC_STATUS_ERR_NO_CHANNEL_ID);
1379 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1381 /* Get channel entry */
1382 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1384 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1385 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1389 /* Check whether this client is on the channel */
1390 if (!silc_server_client_on_channel(id_entry, channel)) {
1391 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1392 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1396 /* Notify routers that they should remove this client from their list
1397 of clients on the channel. */
1398 if (!server->standalone)
1399 silc_server_send_remove_channel_user(server,
1400 server->id_entry->router->connection,
1401 server->server_type == SILC_ROUTER ?
1402 TRUE : FALSE, id_entry->id, id);
1404 /* Remove client from channel */
1405 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
1407 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1410 /* If the channel does not exist anymore we won't send anything */
1414 /* Re-generate channel key */
1415 key_len = channel->key_len / 8;
1416 for (i = 0; i < key_len; i++)
1417 channel_key[i] = silc_rng_get_byte(server->rng);
1418 channel->channel_key->cipher->set_key(channel->channel_key->context,
1419 channel_key, key_len);
1420 memset(channel->key, 0, key_len);
1421 silc_free(channel->key);
1422 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1423 memcpy(channel->key, channel_key, key_len);
1424 memset(channel_key, 0, sizeof(channel_key));
1426 /* Encode channel key payload to be distributed on the channel */
1428 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1429 strlen(channel->channel_key->cipher->name),
1430 channel->channel_key->cipher->name,
1431 key_len, channel->key);
1433 /* If we are normal server then we will send it to our router. If we
1434 are router we will send it to all local servers that has clients on
1436 if (server->server_type == SILC_SERVER) {
1437 if (!server->standalone)
1438 silc_server_packet_send(server,
1439 cmd->server->id_entry->router->connection,
1440 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1446 /* Send to locally connected clients on the channel */
1447 silc_server_packet_send_local_channel(server, channel,
1448 SILC_PACKET_CHANNEL_KEY, 0,
1449 packet->data, packet->len, FALSE);
1451 silc_buffer_free(packet);
1455 silc_server_command_free(cmd);
1458 /* Server side of command NAMES. Resolves clients and their names currently
1459 joined on the requested channel. The name list is sent back to the
1462 SILC_SERVER_CMD_FUNC(names)
1464 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1465 SilcServer server = cmd->server;
1466 SilcChannelEntry channel;
1469 unsigned int i, len, len2, argc;
1471 char *name_list = NULL, *n;
1472 SilcBuffer client_id_list;
1474 SILC_LOG_DEBUG(("Start"));
1476 argc = silc_command_get_arg_num(cmd->payload);
1478 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1479 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1484 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1488 /* Get Channel ID */
1489 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1491 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1492 SILC_STATUS_ERR_NO_CHANNEL_ID);
1495 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1497 /* Check whether the channel exists. If we are normal server and the
1498 channel does not exist we will send this same command to our router
1499 which will know if the channel exists. */
1500 channel = silc_idlist_find_channel_by_id(server->local_list, id);
1502 if (server->server_type == SILC_SERVER && !server->standalone) {
1503 /* XXX Send names command */
1505 cmd->pending = TRUE;
1506 silc_server_command_pending(SILC_COMMAND_NAMES,
1507 silc_server_command_names, context);
1511 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1512 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1516 /* Assemble the name list now */
1519 for (i = 0; i < channel->user_list_count; i++) {
1520 if (!channel->user_list[i].client)
1523 n = channel->user_list[i].client->nickname;
1527 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1528 memcpy(name_list + (len - len2), n, len2);
1531 if (i == channel->user_list_count - 1)
1533 memcpy(name_list + len, ",", 1);
1540 /* Assemble the Client ID list now */
1541 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1542 channel->user_list_count);
1543 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1544 channel->user_list_count));
1545 for (i = 0; i < channel->user_list_count; i++) {
1546 unsigned char *id_string;
1548 if (!channel->user_list[i].client)
1551 id_string = silc_id_id2str(channel->user_list[i].client->id,
1553 silc_buffer_format(client_id_list,
1554 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1556 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1557 silc_free(id_string);
1559 silc_buffer_push(client_id_list,
1560 client_id_list->data - client_id_list->head);
1563 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1565 2, tmp, SILC_ID_CHANNEL_LEN,
1568 4, client_id_list->data,
1569 client_id_list->len);
1570 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1571 packet->data, packet->len, FALSE);
1573 silc_buffer_free(packet);
1574 silc_free(name_list);
1575 silc_buffer_free(client_id_list);
1579 silc_server_command_free(cmd);