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);
41 void silc_server_command_send_names(SilcServer server,
42 SilcSocketConnection sock,
43 SilcChannelEntry channel);
45 /* Server command list. */
46 SilcServerCommand silc_command_list[] =
48 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
49 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
50 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
52 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
53 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
55 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
56 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
57 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
58 SILC_SERVER_CMD(connect, CONNECT,
59 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
60 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
61 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
63 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
64 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
65 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
66 SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
67 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
68 SILC_SERVER_CMD(restart, RESTART,
69 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
70 SILC_SERVER_CMD(close, CLOSE,
71 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
72 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
73 SILC_SERVER_CMD(silcoper, SILCOPER,
74 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
75 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
76 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
81 #define SILC_SERVER_COMMAND_CHECK_ARGC(command, context, min, max) \
83 unsigned int _argc = silc_argument_get_arg_num(cmd->args); \
85 SILC_LOG_DEBUG(("Start")); \
88 silc_server_command_send_status_reply(cmd, command, \
89 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \
90 silc_server_command_free(cmd); \
94 silc_server_command_send_status_reply(cmd, command, \
95 SILC_STATUS_ERR_TOO_MANY_PARAMS); \
96 silc_server_command_free(cmd); \
101 /* Returns TRUE if the connection is registered. Unregistered connections
102 usually cannot send commands hence the check. */
104 static int silc_server_is_registered(SilcServer server,
105 SilcSocketConnection sock,
106 SilcServerCommandContext cmd,
109 SilcIDListData idata = (SilcIDListData)sock->user_data;
110 if (idata->registered)
113 silc_server_command_send_status_reply(cmd, command,
114 SILC_STATUS_ERR_NOT_REGISTERED);
115 silc_server_command_free(cmd);
119 /* Processes received command packet. */
121 void silc_server_command_process(SilcServer server,
122 SilcSocketConnection sock,
123 SilcPacketContext *packet)
125 SilcServerCommandContext ctx;
126 SilcServerCommand *cmd;
129 /* XXX allow commands in but do not execute them more than once per
132 /* Check whether it is allowed for this connection to execute any
134 if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
136 SilcClientEntry client = (SilcClientEntry)sock->user_data;
141 /* Allow only one command executed in 2 seconds. */
142 curtime = time(NULL);
143 if (client->last_command && (curtime - client->last_command) < 2)
146 /* Update access time */
147 client->last_command = curtime;
151 /* Allocate command context. This must be free'd by the
152 command routine receiving it. */
153 ctx = silc_calloc(1, sizeof(*ctx));
154 ctx->server = server;
156 ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
158 /* Parse the command payload in the packet */
159 ctx->payload = silc_command_payload_parse(packet->buffer);
161 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
162 silc_buffer_free(packet->buffer);
163 silc_packet_context_free(packet);
167 ctx->args = silc_command_get_args(ctx->payload);
169 /* Execute command. If this fails the packet is dropped. */
170 for (cmd = silc_command_list; cmd->cb; cmd++)
171 if (cmd->cmd == silc_command_get(ctx->payload)) {
173 if (!(cmd->flags & SILC_CF_REG)) {
178 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
185 SILC_LOG_ERROR(("Unknown command, packet dropped"));
186 silc_server_command_free(ctx);
191 /* Add new pending command to be executed when reply to a command has been
192 received. The `reply_cmd' is the command that will call the `callback'
193 with `context' when reply has been received. If `ident' is non-zero
194 the `callback' will be executed when received reply with command
195 identifier `ident'. */
197 void silc_server_command_pending(SilcServer server,
198 SilcCommand reply_cmd,
199 unsigned short ident,
200 SilcCommandCb callback,
203 SilcServerCommandPending *reply;
205 reply = silc_calloc(1, sizeof(*reply));
206 reply->reply_cmd = reply_cmd;
207 reply->ident = ident;
208 reply->context = context;
209 reply->callback = callback;
210 silc_dlist_add(server->pending_commands, reply);
213 /* Deletes pending command by reply command type. */
215 void silc_server_command_pending_del(SilcServer server,
216 SilcCommand reply_cmd,
217 unsigned short ident)
219 SilcServerCommandPending *r;
221 silc_dlist_start(server->pending_commands);
222 while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
223 if (r->reply_cmd == reply_cmd && r->ident == ident) {
224 silc_dlist_del(server->pending_commands, r);
230 /* Checks for pending commands and marks callbacks to be called from
231 the command reply function. Returns TRUE if there were pending command. */
233 int silc_server_command_pending_check(SilcServer server,
234 SilcServerCommandReplyContext ctx,
236 unsigned short ident)
238 SilcServerCommandPending *r;
240 silc_dlist_start(server->pending_commands);
241 while ((r = silc_dlist_get(server->pending_commands)) != SILC_LIST_END) {
242 if (r->reply_cmd == command && r->ident == ident) {
243 ctx->context = r->context;
244 ctx->callback = r->callback;
253 /* Free's the command context allocated before executing the command */
255 static void silc_server_command_free(SilcServerCommandContext cmd)
259 silc_command_free_payload(cmd->payload);
261 silc_packet_context_free(cmd->packet);
266 /* Sends simple status message as command reply packet */
269 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
271 SilcCommandStatus status)
275 SILC_LOG_DEBUG(("Sending command status %d", status));
277 buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
278 silc_server_packet_send(cmd->server, cmd->sock,
279 SILC_PACKET_COMMAND_REPLY, 0,
280 buffer->data, buffer->len, FALSE);
281 silc_buffer_free(buffer);
284 /* Sends command status reply with one extra argument. The argument
285 type must be sent as argument. */
288 silc_server_command_send_status_data(SilcServerCommandContext cmd,
290 SilcCommandStatus status,
291 unsigned int arg_type,
293 unsigned int arg_len)
297 SILC_LOG_DEBUG(("Sending command status %d", status));
299 buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
300 arg_type, arg, arg_len);
301 silc_server_packet_send(cmd->server, cmd->sock,
302 SILC_PACKET_COMMAND_REPLY, 0,
303 buffer->data, buffer->len, FALSE);
304 silc_buffer_free(buffer);
307 /******************************************************************************
311 ******************************************************************************/
314 silc_server_command_whois_parse(SilcServerCommandContext cmd,
315 SilcClientID **client_id,
322 unsigned int argc = silc_argument_get_arg_num(cmd->args);
324 /* If client ID is in the command it must be used instead of nickname */
325 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
327 /* No ID, get the nickname@server string and parse it. */
328 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
330 if (strchr(tmp, '@')) {
331 len = strcspn(tmp, "@");
332 *nickname = silc_calloc(len + 1, sizeof(char));
333 memcpy(*nickname, tmp, len);
334 *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
335 memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
337 *nickname = strdup(tmp);
340 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
341 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
345 /* Command includes ID, use that */
346 *client_id = silc_id_payload_parse_id(tmp, len);
349 /* Get the max count of reply messages allowed */
351 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
353 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
354 SILC_STATUS_ERR_TOO_MANY_PARAMS);
356 silc_free(*nickname);
358 silc_free(*server_name);
369 silc_server_command_whois_check(SilcServerCommandContext cmd,
370 SilcClientEntry *clients,
371 unsigned int clients_count)
373 SilcServer server = cmd->server;
375 SilcClientEntry entry;
377 for (i = 0; i < clients_count; i++) {
380 if (!entry->nickname || !entry->username || !entry->userinfo) {
382 unsigned short old_ident;
384 old_ident = silc_command_get_ident(cmd->payload);
385 silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
386 tmpbuf = silc_command_payload_encode_payload(cmd->payload);
388 /* Send WHOIS command */
389 silc_server_packet_send(server, entry->router->connection,
390 SILC_PACKET_COMMAND, cmd->packet->flags,
391 tmpbuf->data, tmpbuf->len, TRUE);
393 /* Reprocess this packet after received reply */
394 silc_server_command_pending(server, SILC_COMMAND_WHOIS,
395 silc_command_get_ident(cmd->payload),
396 silc_server_command_whois, (void *)cmd);
399 silc_command_set_ident(cmd->payload, old_ident);
401 silc_buffer_free(tmpbuf);
410 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
411 SilcClientEntry *clients,
412 unsigned int clients_count)
414 SilcServer server = cmd->server;
416 int i, count = 0, len;
417 SilcBuffer packet, idp;
418 SilcClientEntry entry;
419 SilcCommandStatus status;
420 unsigned short ident = silc_command_get_ident(cmd->payload);
422 status = SILC_STATUS_OK;
423 if (clients_count > 1)
424 status = SILC_STATUS_LIST_START;
426 for (i = 0; i < clients_count; i++) {
429 if (count && i - 1 == count)
432 if (clients_count > 2)
433 status = SILC_STATUS_LIST_ITEM;
435 if (clients_count > 1 && i == clients_count - 1)
436 status = SILC_STATUS_LIST_END;
438 /* Send WHOIS reply */
439 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
440 tmp = silc_argument_get_first_arg(cmd->args, NULL);
444 char nh[256], uh[256];
445 unsigned char idle[4];
446 SilcSocketConnection hsock;
448 memset(uh, 0, sizeof(uh));
449 memset(nh, 0, sizeof(nh));
451 strncat(nh, entry->nickname, strlen(entry->nickname));
452 if (!strchr(entry->nickname, '@')) {
454 len = entry->router ? strlen(entry->router->server_name) :
455 strlen(server->server_name);
456 strncat(nh, entry->router ? entry->router->server_name :
457 server->server_name, len);
460 strncat(uh, entry->username, strlen(entry->username));
461 if (!strchr(entry->username, '@')) {
463 hsock = (SilcSocketConnection)entry->connection;
464 len = strlen(hsock->hostname);
465 strncat(uh, hsock->hostname, len);
468 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
473 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
475 2, idp->data, idp->len,
479 strlen(entry->userinfo),
483 silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
485 2, idp->data, idp->len,
491 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
492 0, packet->data, packet->len, FALSE);
494 silc_buffer_free(packet);
495 silc_buffer_free(idp);
500 silc_server_command_whois_from_client(SilcServerCommandContext cmd)
502 SilcServer server = cmd->server;
503 char *nick = NULL, *server_name = NULL;
504 int count = 0, clients_count;
505 SilcClientID *client_id = NULL;
506 SilcClientEntry *clients = NULL, entry;
509 /* Parse the whois request */
510 if (!silc_server_command_whois_parse(cmd, &client_id, &nick,
511 &server_name, &count))
514 /* Protocol dictates that we must always send the received WHOIS request
515 to our router if we are normal server, so let's do it now unless we
516 are standalone. We will not send any replies to the client until we
517 have received reply from the router. */
518 if (server->server_type == SILC_SERVER &&
519 !cmd->pending && !server->standalone) {
521 unsigned short old_ident;
523 old_ident = silc_command_get_ident(cmd->payload);
524 silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
525 tmpbuf = silc_command_payload_encode_payload(cmd->payload);
527 /* Send WHOIS command to our router */
528 silc_server_packet_send(server, (SilcSocketConnection)
529 server->router->connection,
530 SILC_PACKET_COMMAND, cmd->packet->flags,
531 tmpbuf->data, tmpbuf->len, TRUE);
533 /* Reprocess this packet after received reply from router */
534 silc_server_command_pending(server, SILC_COMMAND_WHOIS,
535 silc_command_get_ident(cmd->payload),
536 silc_server_command_whois, (void *)cmd);
539 silc_command_set_ident(cmd->payload, old_ident);
541 silc_buffer_free(tmpbuf);
546 /* We are ready to process the command request. Let's search for the
547 requested client and send reply to the requesting client. */
549 /* Get all clients matching that ID or nickname from local list */
551 entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
553 clients = silc_calloc(1, sizeof(*clients));
558 clients = silc_idlist_get_clients_by_nickname(server->local_list,
563 /* Check global list as well */
566 entry = silc_idlist_find_client_by_id(server->global_list,
569 clients = silc_calloc(1, sizeof(*clients));
574 clients = silc_idlist_get_clients_by_nickname(server->global_list,
581 /* Such a client really does not exist in the SILC network. */
582 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
583 SILC_STATUS_ERR_NO_SUCH_NICK,
584 3, nick, strlen(nick));
588 /* Router always finds the client entry if it exists in the SILC network.
589 However, it might be incomplete entry and does not include all the
590 mandatory fields that WHOIS command reply requires. Check for these and
591 make query from the server who owns the client if some fields are
593 if (server->server_type == SILC_ROUTER &&
594 !silc_server_command_whois_check(cmd, clients, clients_count)) {
599 /* Send the command reply to the client */
600 silc_server_command_whois_send_reply(cmd, clients, clients_count);
606 silc_free(client_id);
610 silc_free(server_name);
616 silc_server_command_whois_from_server(SilcServerCommandContext cmd)
618 SilcServer server = cmd->server;
619 char *nick = NULL, *server_name = NULL;
620 int count = 0, clients_count;
621 SilcClientID *client_id = NULL;
622 SilcClientEntry *clients = NULL, entry;
625 /* Parse the whois request */
626 if (!silc_server_command_whois_parse(cmd, &client_id, &nick,
627 &server_name, &count))
630 /* Process the command request. Let's search for the requested client and
631 send reply to the requesting server. */
634 entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
636 clients = silc_calloc(1, sizeof(*clients));
641 clients = silc_idlist_get_clients_by_nickname(server->local_list,
645 clients = silc_idlist_get_clients_by_hash(server->local_list,
646 nick, server->md5hash,
650 /* If we are router we will check our global list as well. */
651 if (!clients && server->server_type == SILC_ROUTER) {
653 entry = silc_idlist_find_client_by_id(server->global_list,
656 clients = silc_calloc(1, sizeof(*clients));
661 clients = silc_idlist_get_clients_by_nickname(server->global_list,
665 clients = silc_idlist_get_clients_by_hash(server->global_list,
666 nick, server->md5hash,
672 /* Such a client really does not exist in the SILC network. */
673 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
674 SILC_STATUS_ERR_NO_SUCH_NICK,
675 3, nick, strlen(nick));
679 /* Router always finds the client entry if it exists in the SILC network.
680 However, it might be incomplete entry and does not include all the
681 mandatory fields that WHOIS command reply requires. Check for these and
682 make query from the server who owns the client if some fields are
684 if (!cmd->pending && server->server_type == SILC_ROUTER &&
685 !silc_server_command_whois_check(cmd, clients, clients_count)) {
690 /* Send the command reply to the client */
691 silc_server_command_whois_send_reply(cmd, clients, clients_count);
697 silc_free(client_id);
701 silc_free(server_name);
706 /* Server side of command WHOIS. Processes user's query and sends found
707 results as command replies back to the client. */
709 SILC_SERVER_CMD_FUNC(whois)
711 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
714 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_WHOIS, cmd, 1, 3);
716 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
717 ret = silc_server_command_whois_from_client(cmd);
719 ret = silc_server_command_whois_from_server(cmd);
722 silc_server_command_free(cmd);
725 SILC_SERVER_CMD_FUNC(whowas)
729 /******************************************************************************
733 ******************************************************************************/
736 silc_server_command_identify_parse(SilcServerCommandContext cmd,
737 SilcClientID **client_id,
744 unsigned int argc = silc_argument_get_arg_num(cmd->args);
746 /* If client ID is in the command it must be used instead of nickname */
747 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
749 /* No ID, get the nickname@server string and parse it. */
750 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
752 if (strchr(tmp, '@')) {
753 len = strcspn(tmp, "@");
754 *nickname = silc_calloc(len + 1, sizeof(char));
755 memcpy(*nickname, tmp, len);
756 *server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
757 memcpy(*server_name, tmp + len + 1, strlen(tmp) - len - 1);
759 *nickname = strdup(tmp);
762 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
763 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
767 /* Command includes ID, use that */
768 *client_id = silc_id_payload_parse_id(tmp, len);
771 /* Get the max count of reply messages allowed */
773 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
775 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
776 SILC_STATUS_ERR_TOO_MANY_PARAMS);
778 silc_free(*nickname);
780 silc_free(*server_name);
791 silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
792 SilcClientEntry *clients,
793 unsigned int clients_count)
795 SilcServer server = cmd->server;
797 int i, count = 0, len;
798 SilcBuffer packet, idp;
799 SilcClientEntry entry;
800 SilcCommandStatus status;
801 unsigned short ident = silc_command_get_ident(cmd->payload);
803 status = SILC_STATUS_OK;
804 if (clients_count > 1)
805 status = SILC_STATUS_LIST_START;
807 for (i = 0; i < clients_count; i++) {
810 if (count && i - 1 == count)
813 if (clients_count > 2)
814 status = SILC_STATUS_LIST_ITEM;
816 if (clients_count > 1 && i == clients_count - 1)
817 status = SILC_STATUS_LIST_END;
819 /* Send IDENTIFY reply */
820 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
821 tmp = silc_argument_get_first_arg(cmd->args, NULL);
825 char nh[256], uh[256];
826 SilcSocketConnection hsock;
828 memset(uh, 0, sizeof(uh));
829 memset(nh, 0, sizeof(nh));
831 strncat(nh, entry->nickname, strlen(entry->nickname));
832 if (!strchr(entry->nickname, '@')) {
834 len = entry->router ? strlen(entry->router->server_name) :
835 strlen(server->server_name);
836 strncat(nh, entry->router ? entry->router->server_name :
837 server->server_name, len);
840 if (!entry->username) {
841 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
842 SILC_STATUS_OK, ident, 2,
843 2, idp->data, idp->len,
846 strncat(uh, entry->username, strlen(entry->username));
847 if (!strchr(entry->username, '@')) {
849 hsock = (SilcSocketConnection)entry->connection;
850 len = strlen(hsock->hostname);
851 strncat(uh, hsock->hostname, len);
854 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
855 SILC_STATUS_OK, ident, 3,
856 2, idp->data, idp->len,
861 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
862 0, packet->data, packet->len, FALSE);
864 silc_buffer_free(packet);
865 silc_buffer_free(idp);
871 silc_server_command_identify_from_client(SilcServerCommandContext cmd)
873 SilcServer server = cmd->server;
874 char *nick = NULL, *server_name = NULL;
875 int count = 0, clients_count;
876 SilcClientID *client_id = NULL;
877 SilcClientEntry *clients = NULL, entry;
880 /* Parse the IDENTIFY request */
881 if (!silc_server_command_identify_parse(cmd, &client_id, &nick,
882 &server_name, &count))
885 /* Protocol dictates that we must always send the received IDENTIFY request
886 to our router if we are normal server, so let's do it now unless we
887 are standalone. We will not send any replies to the client until we
888 have received reply from the router. */
889 if (server->server_type == SILC_SERVER &&
890 !cmd->pending && !server->standalone) {
892 unsigned short old_ident;
894 old_ident = silc_command_get_ident(cmd->payload);
895 silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
896 tmpbuf = silc_command_payload_encode_payload(cmd->payload);
898 /* Send IDENTIFY command to our router */
899 silc_server_packet_send(server, (SilcSocketConnection)
900 server->router->connection,
901 SILC_PACKET_COMMAND, cmd->packet->flags,
902 tmpbuf->data, tmpbuf->len, TRUE);
904 /* Reprocess this packet after received reply from router */
905 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
906 silc_command_get_ident(cmd->payload),
907 silc_server_command_identify, (void *)cmd);
910 silc_command_set_ident(cmd->payload, old_ident);
912 silc_buffer_free(tmpbuf);
917 /* We are ready to process the command request. Let's search for the
918 requested client and send reply to the requesting client. */
920 /* Get all clients matching that ID or nickname from local list */
922 entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
924 clients = silc_calloc(1, sizeof(*clients));
929 clients = silc_idlist_get_clients_by_nickname(server->local_list,
934 /* Check global list as well */
937 entry = silc_idlist_find_client_by_id(server->global_list,
940 clients = silc_calloc(1, sizeof(*clients));
945 clients = silc_idlist_get_clients_by_nickname(server->global_list,
952 /* Such a client really does not exist in the SILC network. */
953 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
954 SILC_STATUS_ERR_NO_SUCH_NICK,
955 3, nick, strlen(nick));
959 /* Send the command reply to the client */
960 silc_server_command_identify_send_reply(cmd, clients, clients_count);
966 silc_free(client_id);
970 silc_free(server_name);
976 silc_server_command_identify_from_server(SilcServerCommandContext cmd)
978 SilcServer server = cmd->server;
979 char *nick = NULL, *server_name = NULL;
980 int count = 0, clients_count;
981 SilcClientID *client_id = NULL;
982 SilcClientEntry *clients = NULL, entry;
985 /* Parse the IDENTIFY request */
986 if (!silc_server_command_identify_parse(cmd, &client_id, &nick,
987 &server_name, &count))
990 /* Process the command request. Let's search for the requested client and
991 send reply to the requesting server. */
994 entry = silc_idlist_find_client_by_id(server->local_list, client_id, NULL);
996 clients = silc_calloc(1, sizeof(*clients));
1001 clients = silc_idlist_get_clients_by_nickname(server->local_list,
1005 clients = silc_idlist_get_clients_by_hash(server->local_list,
1006 nick, server->md5hash,
1010 /* If we are router we will check our global list as well. */
1011 if (!clients && server->server_type == SILC_ROUTER) {
1013 entry = silc_idlist_find_client_by_id(server->global_list,
1016 clients = silc_calloc(1, sizeof(*clients));
1021 clients = silc_idlist_get_clients_by_nickname(server->global_list,
1025 clients = silc_idlist_get_clients_by_hash(server->global_list,
1026 nick, server->md5hash,
1032 /* Such a client really does not exist in the SILC network. */
1033 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
1034 SILC_STATUS_ERR_NO_SUCH_NICK,
1035 3, nick, strlen(nick));
1039 /* Send the command reply to the client */
1040 silc_server_command_identify_send_reply(cmd, clients, clients_count);
1046 silc_free(client_id);
1050 silc_free(server_name);
1055 SILC_SERVER_CMD_FUNC(identify)
1057 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1060 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_IDENTIFY, cmd, 1, 3);
1062 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1063 ret = silc_server_command_identify_from_client(cmd);
1065 ret = silc_server_command_identify_from_server(cmd);
1068 silc_server_command_free(cmd);
1071 /* Checks string for bad characters and returns TRUE if they are found. */
1073 static int silc_server_command_bad_chars(char *nick)
1075 if (strchr(nick, '\\')) return TRUE;
1076 if (strchr(nick, '\"')) return TRUE;
1077 if (strchr(nick, '´')) return TRUE;
1078 if (strchr(nick, '`')) return TRUE;
1079 if (strchr(nick, '\'')) return TRUE;
1080 if (strchr(nick, '*')) return TRUE;
1081 if (strchr(nick, '/')) return TRUE;
1082 if (strchr(nick, '@')) return TRUE;
1087 /* Server side of command NICK. Sets nickname for user. Setting
1088 nickname causes generation of a new client ID for the client. The
1089 new client ID is sent to the client after changing the nickname. */
1091 SILC_SERVER_CMD_FUNC(nick)
1093 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1094 SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1095 SilcServer server = cmd->server;
1096 SilcBuffer packet, nidp, oidp;
1097 SilcClientID *new_id;
1100 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NICK, cmd, 1, 1);
1102 /* Check nickname */
1103 nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
1104 if (silc_server_command_bad_chars(nick) == TRUE) {
1105 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
1106 SILC_STATUS_ERR_BAD_NICKNAME);
1110 /* Create new Client ID */
1111 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
1112 cmd->server->md5hash, nick,
1115 /* Send notify about nickname change to our router. We send the new
1116 ID and ask to replace it with the old one. If we are router the
1117 packet is broadcasted. */
1118 if (!cmd->server->standalone)
1119 silc_server_send_replace_id(server, server->router->connection,
1120 server->server_type == SILC_SERVER ?
1121 FALSE : TRUE, client->id,
1122 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
1123 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
1125 /* Remove old cache entry */
1126 silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
1129 oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1133 memset(client->id, 0, SILC_ID_CLIENT_LEN);
1134 silc_free(client->id);
1137 /* Save the nickname as this client is our local client */
1138 if (client->nickname)
1139 silc_free(client->nickname);
1141 client->nickname = strdup(nick);
1142 client->id = new_id;
1144 /* Update client cache */
1145 silc_idcache_add(server->local_list->clients, client->nickname,
1146 SILC_ID_CLIENT, client->id, (void *)client, TRUE);
1148 nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1150 /* Send NICK_CHANGE notify */
1151 silc_server_send_notify_on_channels(server, client,
1152 SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
1153 oidp->data, oidp->len,
1154 nidp->data, nidp->len);
1156 /* Send the new Client ID as reply command back to client */
1157 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
1158 SILC_STATUS_OK, 0, 1,
1159 2, nidp->data, nidp->len);
1160 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1161 0, packet->data, packet->len, FALSE);
1163 silc_buffer_free(packet);
1164 silc_buffer_free(nidp);
1165 silc_buffer_free(oidp);
1168 silc_server_command_free(cmd);
1171 SILC_SERVER_CMD_FUNC(list)
1175 /* Server side of TOPIC command. Sets topic for channel and/or returns
1176 current topic to client. */
1178 SILC_SERVER_CMD_FUNC(topic)
1180 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1181 SilcServer server = cmd->server;
1182 SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
1183 SilcChannelID *channel_id;
1184 SilcChannelEntry channel;
1185 SilcChannelClientEntry chl;
1186 SilcBuffer packet, idp;
1188 unsigned int argc, tmp_len;
1190 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_TOPIC, cmd, 1, 2);
1192 argc = silc_argument_get_arg_num(cmd->args);
1194 /* Get Channel ID */
1195 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1197 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1198 SILC_STATUS_ERR_NO_CHANNEL_ID);
1201 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1203 /* Check whether the channel exists */
1204 channel = silc_idlist_find_channel_by_id(server->local_list,
1207 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1208 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1214 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1216 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1217 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1221 if (strlen(tmp) > 256) {
1222 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1223 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1227 /* See whether has rights to change topic */
1228 silc_list_start(channel->user_list);
1229 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
1230 if (chl->client == client) {
1231 if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1232 silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
1233 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1241 /* Set the topic for channel */
1243 silc_free(channel->topic);
1244 channel->topic = strdup(tmp);
1246 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1248 /* Send notify about topic change to all clients on the channel */
1249 silc_server_send_notify_to_channel(server, channel, TRUE,
1250 SILC_NOTIFY_TYPE_TOPIC_SET, 2,
1251 idp->data, idp->len,
1252 channel->topic, strlen(channel->topic));
1253 silc_buffer_free(idp);
1256 /* Send the topic to client as reply packet */
1257 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1259 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
1260 SILC_STATUS_OK, 0, 2,
1261 2, idp->data, idp->len,
1263 strlen(channel->topic));
1265 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
1266 SILC_STATUS_OK, 0, 1,
1267 2, idp->data, idp->len);
1268 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
1269 0, packet->data, packet->len, FALSE);
1271 silc_buffer_free(packet);
1272 silc_buffer_free(idp);
1273 silc_free(channel_id);
1276 silc_server_command_free(cmd);
1279 /* Server side of INVITE command. Invites some client to join some channel. */
1281 SILC_SERVER_CMD_FUNC(invite)
1283 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1284 SilcServer server = cmd->server;
1285 SilcSocketConnection sock = cmd->sock, dest_sock;
1286 SilcClientEntry sender, dest;
1287 SilcClientID *dest_id;
1288 SilcChannelEntry channel;
1289 SilcChannelID *channel_id;
1294 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
1296 /* Get destination ID */
1297 tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1299 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1300 SILC_STATUS_ERR_NO_CLIENT_ID);
1303 dest_id = silc_id_payload_parse_id(tmp, len);
1305 /* Get Channel ID */
1306 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1308 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1309 SILC_STATUS_ERR_NO_CHANNEL_ID);
1312 channel_id = silc_id_payload_parse_id(tmp, len);
1314 /* Check whether the channel exists */
1315 channel = silc_idlist_find_channel_by_id(server->local_list,
1318 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1319 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1323 /* Check whether the sender of this command is on the channel. */
1324 sender = (SilcClientEntry)sock->user_data;
1325 if (!silc_server_client_on_channel(sender, channel)) {
1326 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1327 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1331 /* Check whether the channel is invite-only channel. If yes then the
1332 sender of this command must be at least channel operator. */
1333 if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1334 SilcChannelClientEntry chl;
1336 silc_list_start(channel->user_list);
1337 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
1338 if (chl->client == sender) {
1339 if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
1340 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1341 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
1348 /* Find the connection data for the destination. If it is local we will
1349 send it directly otherwise we will send it to router for routing. */
1350 dest = silc_idlist_find_client_by_id(server->local_list, dest_id, NULL);
1352 dest_sock = (SilcSocketConnection)dest->connection;
1354 dest_sock = silc_server_route_get(server, dest_id, SILC_ID_CLIENT);
1356 /* Check whether the requested client is already on the channel. */
1357 /* XXX if we are normal server we don't know about global clients on
1358 the channel thus we must request it (NAMES command), check from
1359 local cache as well. */
1360 if (silc_server_client_on_channel(dest, channel)) {
1361 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1362 SILC_STATUS_ERR_USER_ON_CHANNEL);
1366 sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
1368 /* Send notify to the client that is invited to the channel */
1369 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
1370 SILC_NOTIFY_TYPE_INVITE, 2,
1371 sidp->data, sidp->len, tmp, len);
1373 /* Send command reply */
1374 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1377 silc_buffer_free(sidp);
1380 silc_server_command_free(cmd);
1383 /* Quits connection to client. This gets called if client won't
1384 close the connection even when it has issued QUIT command. */
1386 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
1388 SilcServer server = (SilcServer)context;
1389 SilcSocketConnection sock = server->sockets[fd];
1391 /* Free all client specific data, such as client entry and entires
1392 on channels this client may be on. */
1393 silc_server_free_sock_user_data(server, sock);
1395 /* Close the connection on our side */
1396 silc_server_close_connection(server, sock);
1399 /* Quits SILC session. This is the normal way to disconnect client. */
1401 SILC_SERVER_CMD_FUNC(quit)
1403 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1404 SilcServer server = cmd->server;
1405 SilcSocketConnection sock = cmd->sock;
1407 SILC_LOG_DEBUG(("Start"));
1409 /* We quit the connection with little timeout */
1410 silc_task_register(server->timeout_queue, sock->sock,
1411 silc_server_command_quit_cb, server,
1412 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1414 silc_server_command_free(cmd);
1417 SILC_SERVER_CMD_FUNC(kill)
1421 /* Server side of command INFO. This sends information about us to
1422 the client. If client requested specific server we will send the
1423 command to that server. */
1425 SILC_SERVER_CMD_FUNC(info)
1427 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1428 SilcServer server = cmd->server;
1429 SilcBuffer packet, idp;
1431 char info_string[256], *dest_server;
1433 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 1);
1435 /* Get server name */
1436 dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
1438 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
1439 SILC_STATUS_ERR_NO_SUCH_SERVER);
1443 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
1444 /* Send our reply */
1445 memset(info_string, 0, sizeof(info_string));
1446 snprintf(info_string, sizeof(info_string),
1447 "location: %s server: %s admin: %s <%s>",
1448 server->config->admin_info->location,
1449 server->config->admin_info->server_type,
1450 server->config->admin_info->admin_name,
1451 server->config->admin_info->admin_email);
1453 idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
1455 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
1456 SILC_STATUS_OK, 0, 2,
1457 2, idp->data, idp->len,
1459 strlen(info_string));
1460 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1461 packet->data, packet->len, FALSE);
1463 silc_buffer_free(packet);
1464 silc_buffer_free(idp);
1466 /* Send this command to the requested server */
1468 if (server->server_type == SILC_SERVER && !server->standalone) {
1472 if (server->server_type == SILC_ROUTER) {
1478 silc_server_command_free(cmd);
1481 SILC_SERVER_CMD_FUNC(connect)
1485 /* Server side of command PING. This just replies to the ping. */
1487 SILC_SERVER_CMD_FUNC(ping)
1489 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1490 SilcServer server = cmd->server;
1495 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INFO, cmd, 1, 2);
1498 tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
1500 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1501 SILC_STATUS_ERR_NO_SERVER_ID);
1504 id = silc_id_str2id(tmp, SILC_ID_SERVER);
1508 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
1509 /* Send our reply */
1510 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1513 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
1514 SILC_STATUS_ERR_NO_SUCH_SERVER);
1521 silc_server_command_free(cmd);
1524 SILC_SERVER_CMD_FUNC(oper)
1533 SilcChannelEntry channel;
1535 SilcClientEntry client;
1536 } JoinInternalContext;
1538 SILC_TASK_CALLBACK(silc_server_command_join_notify)
1540 JoinInternalContext *ctx = (JoinInternalContext *)context;
1542 if (ctx->channel->key && ctx->channel->key_len) {
1545 clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
1547 silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
1548 SILC_NOTIFY_TYPE_JOIN, 1,
1549 clidp->data, clidp->len);
1551 /* Send NEW_CHANNEL_USER packet to primary route */
1552 silc_server_send_new_channel_user(server, server->router->connection,
1553 server->server_type == SILC_SERVER ?
1555 channel->id, SILC_ID_CHANNEL_LEN,
1556 client->id, SILC_ID_CLIENT_LEN);
1559 /* Send NAMES command reply to the joined channel so the user sees who
1560 is currently on the channel. */
1561 silc_server_command_send_names(ctx->server, ctx->client->connection,
1564 silc_buffer_free(clidp);
1567 silc_task_register(ctx->server->timeout_queue, fd,
1568 silc_server_command_join_notify, context,
1569 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1573 /* Assembles NAMES command and executes it. This is called when client
1574 joins to a channel and we wan't to send NAMES command reply to the
1577 void silc_server_command_send_names(SilcServer server,
1578 SilcSocketConnection sock,
1579 SilcChannelEntry channel)
1581 SilcServerCommandContext cmd;
1582 SilcBuffer buffer, idp;
1584 idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1585 buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
1586 1, idp->data, idp->len);
1588 cmd = silc_calloc(1, sizeof(*cmd));
1589 cmd->payload = silc_command_payload_parse(buffer);
1590 cmd->args = silc_command_get_args(cmd->payload);
1591 cmd->server = server;
1593 cmd->pending = FALSE;
1595 silc_server_command_names((void *)cmd);
1600 /* Internal routine that is called after router has replied to server's
1601 JOIN command it forwarded to the router. The route has joined and possibly
1602 creaetd the channel. This function adds the client to the channel's user
1605 SILC_SERVER_CMD_FUNC(add_to_channel)
1607 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1608 SilcServer server = cmd->server;
1609 SilcClientEntry client;
1610 SilcChannelEntry channel;
1611 SilcChannelClientEntry chl;
1614 /* Get channel name */
1615 channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
1617 /* Get client entry */
1618 client = (SilcClientEntry)cmd->sock->user_data;
1620 /* Get channel entry */
1621 channel = silc_idlist_find_channel_by_name(server->local_list,
1622 channel_name, NULL);
1624 /* Join the client to the channel by adding it to channel's user list.
1625 Add also the channel to client entry's channels list for fast cross-
1627 chl = silc_calloc(1, sizeof(*chl));
1628 //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
1629 chl->client = client;
1630 chl->channel = channel;
1631 silc_list_add(channel->user_list, chl);
1632 silc_list_add(client->channels, chl);
1635 silc_server_command_free(cmd);
1638 /* Internal routine to join channel. The channel sent to this function
1639 has been either created or resolved from ID lists. This joins the sent
1640 client to the channel. */
1642 static void silc_server_command_join_channel(SilcServer server,
1643 SilcServerCommandContext cmd,
1644 SilcChannelEntry channel,
1648 SilcSocketConnection sock = cmd->sock;
1650 unsigned int tmp_len;
1651 unsigned char *passphrase = NULL, mode[4];
1652 SilcClientEntry client;
1653 SilcChannelClientEntry chl;
1654 SilcBuffer reply, chidp, clidp;
1659 /* Get passphrase */
1660 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1662 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1663 memcpy(passphrase, tmp, tmp_len);
1667 * Check channel modes
1670 /* Check invite list if channel is invite-only channel */
1671 if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
1672 if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
1673 /* Invite list is specified. Check whether client is invited in the
1674 list. If not, then check whether it has been invited otherwise. */
1677 /* XXX client must be invited to be able to join the channel */
1681 /* Check ban list if set */
1682 if (channel->mode & SILC_CHANNEL_MODE_BAN) {
1686 /* Check the channel passphrase if set. */
1687 if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
1688 if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
1689 strlen(channel->mode_data.passphrase))) {
1690 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1691 SILC_STATUS_ERR_BAD_PASSWORD);
1696 /* Check user count limit if set. */
1697 if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
1698 if (silc_list_count(channel->user_list) + 1 >
1699 channel->mode_data.user_limit) {
1700 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1701 SILC_STATUS_ERR_CHANNEL_IS_FULL);
1707 * Client is allowed to join to the channel. Make it happen.
1710 /* If the JOIN request was forwarded to us we will make a bit slower
1711 query to get the client pointer. Otherwise, we get the client pointer
1713 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1714 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1715 client = silc_idlist_find_client_by_id(server->local_list, id, NULL);
1718 SILC_LOG_ERROR(("Forwarded join command did not find the client who "
1719 "wanted to join the channel"));
1724 client = (SilcClientEntry)sock->user_data;
1727 /* Check whether the client already is on the channel */
1728 if (silc_server_client_on_channel(client, channel)) {
1729 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1730 SILC_STATUS_ERR_USER_ON_CHANNEL);
1734 /* Generate new channel key as protocol dictates */
1736 silc_server_create_channel_key(server, channel, 0);
1738 /* Join the client to the channel by adding it to channel's user list.
1739 Add also the channel to client entry's channels list for fast cross-
1741 chl = silc_calloc(1, sizeof(*chl));
1743 chl->client = client;
1744 chl->channel = channel;
1745 silc_list_add(channel->user_list, chl);
1746 silc_list_add(client->channels, chl);
1748 /* Encode Client ID Payload of the original client who wants to join */
1749 clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
1751 /* Encode command reply packet */
1752 chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
1753 SILC_PUT32_MSB(channel->mode, mode);
1754 if (!channel->topic) {
1756 silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1757 SILC_STATUS_OK, 0, 3,
1758 2, channel->channel_name,
1759 strlen(channel->channel_name),
1760 3, chidp->data, chidp->len,
1764 silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
1765 SILC_STATUS_OK, 0, 4,
1766 2, channel->channel_name,
1767 strlen(channel->channel_name),
1768 3, chidp->data, chidp->len,
1771 strlen(channel->topic));
1774 if (server->server_type == SILC_ROUTER &&
1775 cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1776 /* We are router and server has forwarded this command to us. Send
1777 all replys to the server. */
1780 /* Send command reply destined to the original client */
1781 tmpid = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1782 silc_server_packet_send_dest(cmd->server, sock,
1783 SILC_PACKET_COMMAND_REPLY, 0,
1784 tmpid, cmd->packet->src_id_type,
1785 reply->data, reply->len, FALSE);
1787 /* Distribute new channel key to local cell and local clients. */
1788 silc_server_send_channel_key(server, channel, FALSE);
1790 /* Distribute JOIN notify into the cell for everbody on the channel */
1791 silc_server_send_notify_to_channel(server, channel, FALSE,
1792 SILC_NOTIFY_TYPE_JOIN, 1,
1793 clidp->data, clidp->len);
1795 /* Broadcast NEW_CHANNEL_USER packet to primary route */
1796 silc_server_send_new_channel_user(server, server->router->connection,
1797 TRUE, channel->id, SILC_ID_CHANNEL_LEN,
1798 client->id, SILC_ID_CLIENT_LEN);
1802 /* Client sent the command. Send all replies directly to the client. */
1804 /* Send command reply */
1805 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1806 reply->data, reply->len, FALSE);
1808 /* Send the channel key. Channel key is sent before any other packet
1810 silc_server_send_channel_key(server, channel, server->standalone ?
1813 /* Send JOIN notify to locally connected clients on the channel */
1814 silc_server_send_notify_to_channel(server, channel, FALSE,
1815 SILC_NOTIFY_TYPE_JOIN, 1,
1816 clidp->data, clidp->len);
1818 /* Send NEW_CHANNEL_USER packet to our primary router */
1819 if (!server->standalone)
1820 silc_server_send_new_channel_user(server, server->router->connection,
1822 channel->id, SILC_ID_CHANNEL_LEN,
1823 client->id, SILC_ID_CLIENT_LEN);
1825 /* Send NAMES command reply to the joined channel so the user sees who
1826 is currently on the channel. */
1827 silc_server_command_send_names(server, sock, channel);
1830 silc_buffer_free(reply);
1831 silc_buffer_free(clidp);
1832 silc_buffer_free(chidp);
1836 silc_free(passphrase);
1839 /* Server side of command JOIN. Joins client into requested channel. If
1840 the channel does not exist it will be created. */
1842 SILC_SERVER_CMD_FUNC(join)
1844 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1845 SilcServer server = cmd->server;
1847 char *tmp, *channel_name = NULL, *cipher = NULL;
1848 SilcChannelEntry channel;
1849 unsigned int umode = 0;
1850 int created = FALSE;
1852 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_JOIN, cmd, 1, 3);
1854 /* Get channel name */
1855 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
1857 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1858 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1863 if (silc_server_command_bad_chars(channel_name) == TRUE) {
1864 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1865 SILC_STATUS_ERR_BAD_CHANNEL);
1866 silc_free(channel_name);
1870 /* Get cipher name */
1871 cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
1873 /* See if the channel exists */
1874 channel = silc_idlist_find_channel_by_name(server->local_list,
1875 channel_name, NULL);
1877 /* Channel not found */
1879 /* If we are standalone server we don't have a router, we just create
1880 the channel by ourselves. */
1881 if (server->standalone) {
1882 channel = silc_server_create_new_channel(server, server->id, cipher,
1884 umode |= SILC_CHANNEL_UMODE_CHANOP;
1885 umode |= SILC_CHANNEL_UMODE_CHANFO;
1889 /* The channel does not exist on our server. If we are normal server
1890 we will send JOIN command to our router which will handle the joining
1891 procedure (either creates the channel if it doesn't exist or joins
1892 the client to it). */
1893 if (server->server_type == SILC_SERVER) {
1894 /* Forward the original JOIN command to the router */
1895 silc_buffer_push(cmd->packet->buffer,
1896 cmd->packet->buffer->data -
1897 cmd->packet->buffer->head);
1898 silc_server_packet_forward(server, (SilcSocketConnection)
1899 server->router->connection,
1900 cmd->packet->buffer->data,
1901 cmd->packet->buffer->len, TRUE);
1903 /* Register handler that will be called after the router has replied
1904 to us. We will add the client to the new channel in this callback
1905 function. Will be called from JOIN command reply. */
1906 silc_server_command_pending(server, SILC_COMMAND_JOIN,
1907 ++server->router->data.cmd_ident,
1908 silc_server_command_add_to_channel,
1913 /* We are router and the channel does not seem exist so we will check
1914 our global list as well for the channel. */
1915 channel = silc_idlist_find_channel_by_name(server->global_list,
1916 channel_name, NULL);
1918 /* Channel really does not exist, create it */
1919 channel = silc_server_create_new_channel(server, server->id, cipher,
1921 umode |= SILC_CHANNEL_UMODE_CHANOP;
1922 umode |= SILC_CHANNEL_UMODE_CHANFO;
1928 /* Join to the channel */
1929 silc_server_command_join_channel(server, cmd, channel, created, umode);
1932 silc_server_command_free(cmd);
1935 /* Server side of command MOTD. Sends server's current "message of the
1936 day" to the client. */
1938 SILC_SERVER_CMD_FUNC(motd)
1940 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1941 SilcServer server = cmd->server;
1945 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
1947 /* XXX show currently only our motd */
1949 if (server->config && server->config->motd &&
1950 server->config->motd->motd_file) {
1953 motd = silc_file_read(server->config->motd->motd_file, &motd_len);
1958 silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
1964 silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
1969 silc_server_command_free(cmd);
1972 SILC_SERVER_CMD_FUNC(umode)
1976 /* Checks that client has rights to add or remove channel modes. If any
1977 of the checks fails FALSE is returned. */
1979 int silc_server_check_cmode_rights(SilcChannelEntry channel,
1980 SilcChannelClientEntry client,
1983 int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
1984 int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
1986 /* Check whether has rights to change anything */
1987 if (!is_op && !is_fo)
1990 /* Check whether has rights to change everything */
1994 /* We know that client is channel operator, check that they are not
1995 changing anything that requires channel founder rights. Rest of the
1996 modes are available automatically for channel operator. */
1998 if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
1999 if (is_op && !is_fo)
2002 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2003 if (is_op && !is_fo)
2008 if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2009 if (is_op && !is_fo)
2012 if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2013 if (is_op && !is_fo)
2018 if (mode & SILC_CHANNEL_MODE_CIPHER) {
2019 if (is_op && !is_fo)
2022 if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2023 if (is_op && !is_fo)
2031 /* Server side command of CMODE. Changes channel mode */
2033 SILC_SERVER_CMD_FUNC(cmode)
2035 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2036 SilcServer server = cmd->server;
2037 SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2038 SilcChannelID *channel_id;
2039 SilcChannelEntry channel;
2040 SilcChannelClientEntry chl;
2041 SilcBuffer packet, cidp;
2042 unsigned char *tmp, *tmp_id, *tmp_mask;
2043 unsigned int argc, mode_mask, tmp_len, tmp_len2;
2045 SILC_LOG_DEBUG(("Start"));
2047 argc = silc_argument_get_arg_num(cmd->args);
2049 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2050 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2054 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2055 SILC_STATUS_ERR_TOO_MANY_PARAMS);
2059 /* Get Channel ID */
2060 tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
2062 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2063 SILC_STATUS_ERR_NO_CHANNEL_ID);
2066 channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
2068 /* Get the channel mode mask */
2069 tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2071 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2072 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2075 SILC_GET32_MSB(mode_mask, tmp_mask);
2077 /* Get channel entry */
2078 channel = silc_idlist_find_channel_by_id(server->local_list,
2081 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2082 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2086 /* Check whether this client is on the channel */
2087 if (!silc_server_client_on_channel(client, channel)) {
2088 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2089 SILC_STATUS_ERR_NOT_ON_CHANNEL);
2093 /* Get entry to the channel user list */
2094 silc_list_start(channel->user_list);
2095 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2096 if (chl->client == client)
2099 /* Check that client has rights to change any requested channel modes */
2100 if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
2101 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2102 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2107 * Check the modes. Modes that requires nothing special operation are
2111 if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
2112 /* Channel uses private keys to protect traffic. Client(s) has set the
2113 key locally they want to use, server does not know that key. */
2114 /* Nothing interesting to do here now */
2116 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
2117 /* The mode is removed and we need to generate and distribute
2118 new channel key. Clients are not using private channel keys
2119 anymore after this. */
2121 /* XXX Duplicated code, make own function for this!! LEAVE uses this
2124 /* Re-generate channel key */
2125 silc_server_create_channel_key(server, channel, 0);
2127 /* Encode channel key payload to be distributed on the channel */
2129 silc_channel_key_payload_encode(tmp_len2, tmp_id,
2130 strlen(channel->channel_key->
2132 channel->channel_key->cipher->name,
2133 channel->key_len / 8, channel->key);
2135 /* If we are normal server then we will send it to our router. If we
2136 are router we will send it to all local servers that has clients on
2138 if (server->server_type == SILC_SERVER) {
2139 if (!server->standalone)
2140 silc_server_packet_send(server,
2141 cmd->server->router->connection,
2142 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2148 /* Send to locally connected clients on the channel */
2149 silc_server_packet_send_local_channel(server, channel,
2150 SILC_PACKET_CHANNEL_KEY, 0,
2151 packet->data, packet->len, FALSE);
2152 silc_buffer_free(packet);
2156 if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
2157 /* User limit is set on channel */
2158 unsigned int user_limit;
2160 /* Get user limit */
2161 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
2163 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
2164 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2165 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2169 SILC_GET32_MSB(user_limit, tmp);
2170 channel->mode_data.user_limit = user_limit;
2173 if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
2174 /* User limit mode is unset. Remove user limit */
2175 channel->mode_data.user_limit = 0;
2178 if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
2179 if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
2180 /* Passphrase has been set to channel */
2182 /* Get the passphrase */
2183 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
2185 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2186 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2190 /* Save the passphrase */
2191 channel->mode_data.passphrase = strdup(tmp);
2194 if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
2195 /* Passphrase mode is unset. remove the passphrase */
2196 if (channel->mode_data.passphrase) {
2197 silc_free(channel->mode_data.passphrase);
2198 channel->mode_data.passphrase = NULL;
2203 if (mode_mask & SILC_CHANNEL_MODE_BAN) {
2204 if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
2205 /* Ban list is specified for channel */
2208 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
2210 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2211 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2215 /* XXX check that channel founder is not banned */
2217 /* Save the ban list */
2218 channel->mode_data.ban_list = strdup(tmp);
2221 if (channel->mode & SILC_CHANNEL_MODE_BAN) {
2222 /* Ban mode is unset. Remove the entire ban list */
2223 if (channel->mode_data.ban_list) {
2224 silc_free(channel->mode_data.ban_list);
2225 channel->mode_data.ban_list = NULL;
2230 if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
2231 if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
2232 /* Invite list is specified for channel */
2234 /* Get invite list */
2235 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
2237 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2238 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2242 /* Save the invite linst */
2243 channel->mode_data.invite_list = strdup(tmp);
2246 if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
2247 /* Invite list mode is unset. Remove the entire invite list */
2248 if (channel->mode_data.invite_list) {
2249 silc_free(channel->mode_data.invite_list);
2250 channel->mode_data.invite_list = NULL;
2255 if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
2256 if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
2257 /* Cipher to use protect the traffic */
2258 unsigned int key_len = 128;
2262 tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
2264 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
2265 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2269 cp = strchr(tmp, ':');
2275 /* XXX Duplicated code, make own function for this!! */
2277 /* Delete old cipher and allocate the new one */
2278 silc_cipher_free(channel->channel_key);
2279 silc_cipher_alloc(tmp, &channel->channel_key);
2285 /* Re-generate channel key */
2286 silc_server_create_channel_key(server, channel, key_len);
2288 /* Encode channel key payload to be distributed on the channel */
2290 silc_channel_key_payload_encode(tmp_len2, tmp_id,
2291 strlen(channel->channel_key->
2293 channel->channel_key->cipher->name,
2294 channel->key_len / 8, channel->key);
2296 /* If we are normal server then we will send it to our router. If we
2297 are router we will send it to all local servers that has clients on
2299 if (server->server_type == SILC_SERVER) {
2300 if (!server->standalone)
2301 silc_server_packet_send(server,
2302 cmd->server->router->connection,
2303 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2309 /* Send to locally connected clients on the channel */
2310 silc_server_packet_send_local_channel(server, channel,
2311 SILC_PACKET_CHANNEL_KEY, 0,
2312 packet->data, packet->len, FALSE);
2313 silc_buffer_free(packet);
2316 if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
2317 /* Cipher mode is unset. Remove the cipher and revert back to
2320 if (channel->mode_data.cipher) {
2321 silc_free(channel->mode_data.cipher);
2322 channel->mode_data.cipher = NULL;
2323 channel->mode_data.key_len = 0;
2326 /* Generate new cipher and key for the channel */
2328 /* XXX Duplicated code, make own function for this!! */
2330 /* Delete old cipher and allocate default one */
2331 silc_cipher_free(channel->channel_key);
2332 if (!channel->cipher)
2333 silc_cipher_alloc("twofish", &channel->channel_key);
2335 silc_cipher_alloc(channel->cipher, &channel->channel_key);
2337 /* Re-generate channel key */
2338 silc_server_create_channel_key(server, channel, 0);
2340 /* Encode channel key payload to be distributed on the channel */
2342 silc_channel_key_payload_encode(tmp_len2, tmp_id,
2343 strlen(channel->channel_key->
2345 channel->channel_key->cipher->name,
2346 channel->key_len / 8, channel->key);
2348 /* If we are normal server then we will send it to our router. If we
2349 are router we will send it to all local servers that has clients on
2351 if (server->server_type == SILC_SERVER) {
2352 if (!server->standalone)
2353 silc_server_packet_send(server,
2354 cmd->server->router->connection,
2355 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2361 /* Send to locally connected clients on the channel */
2362 silc_server_packet_send_local_channel(server, channel,
2363 SILC_PACKET_CHANNEL_KEY, 0,
2364 packet->data, packet->len, FALSE);
2365 silc_buffer_free(packet);
2369 /* Finally, set the mode */
2370 channel->mode = mode_mask;
2372 /* Send CMODE_CHANGE notify */
2373 cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2374 silc_server_send_notify_to_channel(server, channel, TRUE,
2375 SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
2376 cidp->data, cidp->len,
2380 /* Send command reply to sender */
2381 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
2382 SILC_STATUS_OK, 0, 1,
2384 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
2385 packet->data, packet->len, FALSE);
2387 silc_buffer_free(packet);
2388 silc_free(channel_id);
2391 silc_server_command_free(cmd);
2394 /* Server side of CUMODE command. Changes client's mode on a channel. */
2396 SILC_SERVER_CMD_FUNC(cumode)
2398 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2399 SilcServer server = cmd->server;
2400 SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
2401 SilcChannelID *channel_id;
2402 SilcClientID *client_id;
2403 SilcChannelEntry channel;
2404 SilcClientEntry target_client;
2405 SilcChannelClientEntry chl;
2406 SilcBuffer packet, idp;
2407 unsigned char *tmp_id, *tmp_mask;
2408 unsigned int target_mask, sender_mask, tmp_len;
2411 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_CUMODE, cmd, 3, 3);
2413 /* Get Channel ID */
2414 tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2416 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2417 SILC_STATUS_ERR_NO_CHANNEL_ID);
2420 channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2422 /* Get channel entry */
2423 channel = silc_idlist_find_channel_by_id(server->local_list,
2426 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2427 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2431 /* Check whether sender is on the channel */
2432 if (!silc_server_client_on_channel(client, channel)) {
2433 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2434 SILC_STATUS_ERR_NOT_ON_CHANNEL);
2438 /* Check that client has rights to change other's rights */
2439 silc_list_start(channel->user_list);
2440 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2441 if (chl->client == client) {
2442 if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
2443 !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2444 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2445 SILC_STATUS_ERR_NO_CHANNEL_PRIV);
2449 sender_mask = chl->mode;
2454 /* Get the target client's channel mode mask */
2455 tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
2457 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2458 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2461 SILC_GET32_MSB(target_mask, tmp_mask);
2463 /* Get target Client ID */
2464 tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2466 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2467 SILC_STATUS_ERR_NO_CHANNEL_ID);
2470 client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
2472 /* Get target client's entry */
2473 target_client = silc_idlist_find_client_by_id(server->local_list,
2475 if (!target_client) {
2476 /* XXX If target client is not one of mine send to primary route */
2479 /* Check whether target client is on the channel */
2480 if (!silc_server_client_on_channel(target_client, channel)) {
2481 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2482 SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
2486 /* Get entry to the channel user list */
2487 silc_list_start(channel->user_list);
2488 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
2489 if (chl->client == target_client)
2496 /* If the target client is founder, no one else can change their mode
2498 if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
2499 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2500 SILC_STATUS_ERR_NOT_YOU);
2504 if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
2505 /* Cannot promote anyone to channel founder */
2506 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2507 SILC_STATUS_ERR_NOT_YOU);
2510 if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
2511 if (target_client == client) {
2512 /* Remove channel founder rights from itself */
2513 chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
2516 silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
2517 SILC_STATUS_ERR_NOT_YOU);
2523 if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
2524 /* Promote to operator */
2525 if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
2526 chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
2530 if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
2531 /* Demote to normal user */
2532 chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
2537 /* Send notify to channel, notify only if mode was actually changed. */
2539 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
2540 silc_server_send_notify_to_channel(server, channel, TRUE,
2541 SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
2542 idp->data, idp->len,
2543 tmp_mask, 4, tmp_id, tmp_len);
2544 silc_buffer_free(idp);
2547 /* Send command reply to sender */
2548 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
2549 SILC_STATUS_OK, 0, 2,
2551 3, tmp_id, tmp_len);
2552 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
2553 packet->data, packet->len, FALSE);
2555 silc_buffer_free(packet);
2556 silc_free(channel_id);
2557 silc_free(client_id);
2560 silc_server_command_free(cmd);
2563 /* Server side of KICK command. Kicks client out of channel. */
2565 SILC_SERVER_CMD_FUNC(kick)
2569 SILC_SERVER_CMD_FUNC(restart)
2573 SILC_SERVER_CMD_FUNC(close)
2577 SILC_SERVER_CMD_FUNC(die)
2581 SILC_SERVER_CMD_FUNC(silcoper)
2585 /* Server side command of LEAVE. Removes client from a channel. */
2587 SILC_SERVER_CMD_FUNC(leave)
2589 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2590 SilcServer server = cmd->server;
2591 SilcSocketConnection sock = cmd->sock;
2592 SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
2594 SilcChannelEntry channel;
2596 unsigned int i, len;
2599 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LEAVE, cmd, 1, 2);
2601 /* Get Channel ID */
2602 tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
2604 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2605 SILC_STATUS_ERR_NO_CHANNEL_ID);
2608 id = silc_id_payload_parse_id(tmp, len);
2610 /* Get channel entry */
2611 channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2613 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2614 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2618 /* Check whether this client is on the channel */
2619 if (!silc_server_client_on_channel(id_entry, channel)) {
2620 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2621 SILC_STATUS_ERR_NOT_ON_CHANNEL);
2625 /* Notify routers that they should remove this client from their list
2626 of clients on the channel. */
2627 if (!server->standalone)
2628 silc_server_send_remove_channel_user(server,
2629 server->router->connection,
2630 server->server_type == SILC_ROUTER ?
2631 TRUE : FALSE, id_entry->id, id);
2633 /* Remove client from channel */
2634 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
2636 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2639 /* If the channel does not exist anymore we won't send anything */
2643 /* Re-generate channel key */
2644 silc_server_create_channel_key(server, channel, 0);
2646 /* Encode channel key payload to be distributed on the channel */
2648 silc_channel_key_payload_encode(len, tmp,
2649 strlen(channel->channel_key->cipher->name),
2650 channel->channel_key->cipher->name,
2651 channel->key_len / 8, channel->key);
2653 /* If we are normal server then we will send it to our router. If we
2654 are router we will send it to all local servers that has clients on
2656 if (server->server_type == SILC_SERVER) {
2657 if (!server->standalone)
2658 silc_server_packet_send(server,
2659 cmd->server->router->connection,
2660 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
2666 /* Send to locally connected clients on the channel */
2667 silc_server_packet_send_local_channel(server, channel,
2668 SILC_PACKET_CHANNEL_KEY, 0,
2669 packet->data, packet->len, FALSE);
2671 silc_buffer_free(packet);
2675 silc_server_command_free(cmd);
2678 /* Server side of command NAMES. Resolves clients and their names currently
2679 joined on the requested channel. The name list is sent back to the
2682 SILC_SERVER_CMD_FUNC(names)
2684 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
2685 SilcServer server = cmd->server;
2686 SilcChannelEntry channel;
2687 SilcChannelClientEntry chl;
2690 unsigned int i, len, len2, tmp_len;
2692 char *name_list = NULL, *n;
2693 SilcBuffer client_id_list;
2694 SilcBuffer client_mode_list;
2696 SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_NAMES, cmd, 1, 2);
2698 /* Get Channel ID */
2699 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
2701 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
2702 SILC_STATUS_ERR_NO_CHANNEL_ID);
2705 id = silc_id_payload_parse_id(tmp, tmp_len);
2707 /* Check whether the channel exists. If we are normal server and the
2708 channel does not exist we will send this same command to our router
2709 which will know if the channel exists. */
2710 channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
2712 if (server->server_type == SILC_SERVER && !server->standalone) {
2713 /* XXX Send names command */
2715 cmd->pending = TRUE;
2716 silc_server_command_pending(server, SILC_COMMAND_NAMES, 0,
2717 silc_server_command_names, context);
2721 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
2722 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
2726 /* Assemble the name list now */
2729 silc_list_start(channel->user_list);
2731 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2732 n = chl->client->nickname;
2736 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
2737 memcpy(name_list + (len - len2), n, len2);
2740 if (i == silc_list_count(channel->user_list) - 1)
2742 memcpy(name_list + len, ",", 1);
2750 /* Assemble the Client ID list now */
2751 client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
2752 silc_list_count(channel->user_list));
2753 silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
2754 silc_list_start(channel->user_list);
2755 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2758 idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
2759 silc_buffer_format(client_id_list,
2760 SILC_STR_UI_XNSTRING(idp->data, idp->len),
2762 silc_buffer_pull(client_id_list, idp->len);
2763 silc_buffer_free(idp);
2765 silc_buffer_push(client_id_list,
2766 client_id_list->data - client_id_list->head);
2768 /* Assemble mode list */
2769 client_mode_list = silc_buffer_alloc(4 *
2770 silc_list_count(channel->user_list));
2771 silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
2772 silc_list_start(channel->user_list);
2773 while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
2774 SILC_PUT32_MSB(chl->mode, client_mode_list->data);
2775 silc_buffer_pull(client_mode_list, 4);
2777 silc_buffer_push(client_mode_list,
2778 client_mode_list->data - client_mode_list->head);
2781 packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
2782 SILC_STATUS_OK, 0, 4,
2786 4, client_id_list->data,
2787 client_id_list->len,
2788 5, client_mode_list->data,
2789 client_mode_list->len);
2790 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
2791 packet->data, packet->len, FALSE);
2793 silc_buffer_free(packet);
2794 silc_free(name_list);
2795 silc_buffer_free(client_id_list);
2796 silc_buffer_free(client_mode_list);
2800 silc_server_command_free(cmd);