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.8 2000/07/10 05:42:59 priikone
24 * Removed command packet processing from server.c and added it to
26 * Implemented INFO command. Added support for testing that
27 * connections are registered before executing commands.
29 * Revision 1.7 2000/07/07 06:55:24 priikone
30 * Do not allow client to join twice on same channel.
32 * Revision 1.6 2000/07/06 10:20:59 priikone
33 * Cipher name in joining is not mandatory, removed check.
35 * Revision 1.5 2000/07/06 07:16:43 priikone
36 * Fixed a wrong way of sending command replies. The fixed way
37 * does comply with the protocol.
39 * Revision 1.4 2000/07/05 06:13:38 priikone
40 * Added PING, INVITE and NAMES command.
42 * Revision 1.3 2000/07/03 05:52:22 priikone
43 * Implemented LEAVE command.
45 * Revision 1.2 2000/06/28 05:06:38 priikone
46 * Shorter timeout for channel joining notify.
48 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
49 * Imported from internal CVS/Added Log headers.
54 #include "serverincludes.h"
55 #include "server_internal.h"
57 static int silc_server_is_registered(SilcServer server,
58 SilcSocketConnection sock,
59 SilcServerCommandContext cmd,
62 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
64 SilcCommandStatus status);
66 silc_server_command_send_status_data(SilcServerCommandContext cmd,
68 SilcCommandStatus status,
69 unsigned int arg_type,
71 unsigned int arg_len);
72 static void silc_server_command_free(SilcServerCommandContext cmd);
74 /* Server command list. */
75 SilcServerCommand silc_command_list[] =
77 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
78 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
79 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
80 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
81 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
82 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
83 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
84 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
85 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
86 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
87 SILC_SERVER_CMD(connect, CONNECT,
88 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
89 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
90 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
91 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
92 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
93 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
94 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
95 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
96 SILC_SERVER_CMD(restart, RESTART,
97 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
98 SILC_SERVER_CMD(close, CLOSE,
99 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
100 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
101 SILC_SERVER_CMD(silcoper, SILCOPER,
102 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
103 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
104 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
109 /* List of pending commands. */
110 SilcServerCommandPending *silc_command_pending = NULL;
112 /* Returns TRUE if the connection is registered. Unregistered connections
113 usually cannot send commands hence the check. */
115 static int silc_server_is_registered(SilcServer server,
116 SilcSocketConnection sock,
117 SilcServerCommandContext cmd,
121 case SILC_SOCKET_TYPE_CLIENT:
123 SilcClientList *client = (SilcClientList *)sock->user_data;
124 if (client->registered)
128 case SILC_SOCKET_TYPE_SERVER:
129 case SILC_SOCKET_TYPE_ROUTER:
131 SilcServerList *serv = (SilcServerList *)sock->user_data;
132 if (serv->registered)
140 silc_server_command_send_status_reply(cmd, command,
141 SILC_STATUS_ERR_NOT_REGISTERED);
142 silc_server_command_free(cmd);
146 /* Processes received command packet. */
148 void silc_server_command_process(SilcServer server,
149 SilcSocketConnection sock,
150 SilcPacketContext *packet)
152 SilcServerCommandContext ctx;
153 SilcServerCommand *cmd;
155 /* Allocate command context. This must be free'd by the
156 command routine receiving it. */
157 ctx = silc_calloc(1, sizeof(*ctx));
158 ctx->server = server;
160 ctx->packet = packet; /* Save original packet */
162 /* Parse the command payload in the packet */
163 ctx->payload = silc_command_parse_payload(packet->buffer);
165 SILC_LOG_ERROR(("Bad command payload, packet dropped"));
166 silc_buffer_free(packet->buffer);
171 /* Execute command. If this fails the packet is dropped. */
172 for (cmd = silc_command_list; cmd->cb; cmd++)
173 if (cmd->cmd == silc_command_get(ctx->payload)) {
175 if (!(cmd->flags & SILC_CF_REG)) {
180 if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
187 SILC_LOG_ERROR(("Unknown command, packet dropped"));
192 silc_buffer_free(packet->buffer);
195 /* Add new pending command to the list of pending commands. Currently
196 pending commands are executed from command replies, thus we can
197 execute any command after receiving some specific command reply.
199 The argument `reply_cmd' is the command reply from where the callback
200 function is to be called, thus, it IS NOT the command to be executed. */
202 void silc_server_command_pending(SilcCommand reply_cmd,
203 SilcCommandCb callback,
206 SilcServerCommandPending *reply, *r;
208 reply = silc_calloc(1, sizeof(*reply));
209 reply->reply_cmd = reply_cmd;
210 reply->context = context;
211 reply->callback = callback;
213 if (silc_command_pending == NULL) {
214 silc_command_pending = reply;
218 for (r = silc_command_pending; r; r = r->next) {
219 if (r->next == NULL) {
226 /* Deletes pending command by reply command type. */
228 void silc_server_command_pending_del(SilcCommand reply_cmd)
230 SilcServerCommandPending *r, *tmp;
232 if (silc_command_pending) {
233 if (silc_command_pending->reply_cmd == reply_cmd) {
234 silc_free(silc_command_pending);
235 silc_command_pending = NULL;
239 for (r = silc_command_pending; r; r = r->next) {
240 if (r->next && r->next->reply_cmd == reply_cmd) {
242 r->next = r->next->next;
250 /* Free's the command context allocated before executing the command */
252 static void silc_server_command_free(SilcServerCommandContext cmd)
255 silc_command_free_payload(cmd->payload);
260 #define SILC_COMMAND_STATUS_DATA(x) \
263 /* Sends simple status message as command reply packet */
266 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
268 SilcCommandStatus status)
272 SILC_LOG_DEBUG(("Sending command status %d", status));
274 buffer = silc_command_encode_reply_payload_va(command, status, 0);
275 silc_server_packet_send(cmd->server, cmd->sock,
276 SILC_PACKET_COMMAND_REPLY, 0,
277 buffer->data, buffer->len, FALSE);
278 silc_buffer_free(buffer);
281 /* Sends command status reply with one extra argument. The argument
282 type must be sent as argument. */
285 silc_server_command_send_status_data(SilcServerCommandContext cmd,
287 SilcCommandStatus status,
288 unsigned int arg_type,
290 unsigned int arg_len)
294 SILC_LOG_DEBUG(("Sending command status %d", status));
296 buffer = silc_command_encode_reply_payload_va(command, status, 1,
297 arg_type, arg, arg_len);
298 silc_server_packet_send(cmd->server, cmd->sock,
299 SILC_PACKET_COMMAND_REPLY, 0,
300 buffer->data, buffer->len, FALSE);
301 silc_buffer_free(buffer);
304 /* Server side of command WHOIS. Processes user's query and sends found
305 results as command replies back to the client. */
307 SILC_SERVER_CMD_FUNC(whois)
309 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
310 char *tmp, *nick = NULL, *server = NULL;
311 unsigned int argc, count = 0, len;
312 SilcClientList *entry;
314 unsigned char *id_string;
316 SILC_LOG_DEBUG(("Start"));
318 argc = silc_command_get_arg_num(cmd->payload);
320 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
321 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
325 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
326 SILC_STATUS_ERR_TOO_MANY_PARAMS);
330 /* Get the nickname@server string and parse it. */
331 tmp = silc_command_get_first_arg(cmd->payload, NULL);
333 if (strchr(tmp, '@')) {
334 len = strcspn(tmp, "@");
335 nick = silc_calloc(len + 1, sizeof(char));
336 memcpy(nick, tmp, len);
337 server = silc_calloc(strlen(tmp) - len, sizeof(char));
338 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
343 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
344 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
348 /* Get the max count of reply messages allowed */
350 tmp = silc_command_get_next_arg(cmd->payload, NULL);
352 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
353 SILC_STATUS_ERR_TOO_MANY_PARAMS);
363 /* Then, make the query from our local client list */
364 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
368 /* If we are normal server and are connected to a router we will
369 make global query from the router. */
370 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
375 /* If we are router then we will check our global list as well. */
376 if (cmd->server->server_type == SILC_ROUTER) {
378 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
381 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
382 SILC_STATUS_ERR_NO_SUCH_NICK,
383 3, tmp, strlen(tmp));
389 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
390 SILC_STATUS_ERR_NO_SUCH_NICK,
391 3, tmp, strlen(tmp));
396 /* XXX, works only for local server info */
398 /* Send WHOIS reply */
399 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
400 tmp = silc_command_get_first_arg(cmd->payload, NULL);
403 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
404 char nh[256], uh[256];
405 SilcSocketConnection hsock;
407 memset(uh, 0, sizeof(uh));
408 memset(nh, 0, sizeof(nh));
410 strncat(nh, entry->nickname, strlen(entry->nickname));
412 len = entry->router ? strlen(entry->router->server_name) :
413 strlen(cmd->server->server_name);
414 strncat(nh, entry->router ? entry->router->server_name :
415 cmd->server->server_name, len);
417 strncat(uh, entry->username, strlen(entry->username));
419 hsock = (SilcSocketConnection)entry->connection;
420 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
421 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
426 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
428 2, id_string, SILC_ID_CLIENT_LEN,
432 strlen(entry->userinfo));
435 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
437 2, id_string, SILC_ID_CLIENT_LEN,
444 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
446 2, id_string, SILC_ID_CLIENT_LEN,
448 strlen(entry->nickname),
449 4, tmp, strlen(tmp)); /* XXX */
451 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
452 0, packet->data, packet->len, FALSE);
454 silc_free(id_string);
455 silc_buffer_free(packet);
458 silc_server_command_free(cmd);
461 SILC_SERVER_CMD_FUNC(whowas)
465 SILC_SERVER_CMD_FUNC(identify)
467 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
468 char *tmp, *nick = NULL, *server = NULL;
469 unsigned int argc, count = 0, len;
470 SilcClientList *entry; SilcBuffer packet;
471 unsigned char *id_string;
473 SILC_LOG_DEBUG(("Start"));
475 argc = silc_command_get_arg_num(cmd->payload);
477 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
478 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
482 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
483 SILC_STATUS_ERR_TOO_MANY_PARAMS);
487 /* Get the nickname@server string and parse it. */
488 tmp = silc_command_get_first_arg(cmd->payload, NULL);
490 if (strchr(tmp, '@')) {
491 len = strcspn(tmp, "@");
492 nick = silc_calloc(len + 1, sizeof(char));
493 memcpy(nick, tmp, len);
494 server = silc_calloc(strlen(tmp) - len, sizeof(char));
495 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
500 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
501 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
505 /* Get the max count of reply messages allowed */
507 tmp = silc_command_get_next_arg(cmd->payload, NULL);
509 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
510 SILC_STATUS_ERR_TOO_MANY_PARAMS);
516 /* Then, make the query from our local client list */
517 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
518 nick, cmd->server->md5hash);
521 /* If we are normal server and are connected to a router we will
522 make global query from the router. */
523 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
524 SilcBuffer buffer = cmd->packet->buffer;
526 /* Send IDENTIFY command to our router */
527 silc_buffer_push(buffer, buffer->data - buffer->head);
528 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
529 cmd->server->id_entry->router->connection,
530 buffer->data, buffer->len, TRUE);
534 /* If we are router then we will check our global list as well. */
535 if (cmd->server->server_type == SILC_ROUTER) {
537 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
538 nick, cmd->server->md5hash);
540 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
541 SILC_STATUS_ERR_NO_SUCH_NICK,
542 3, tmp, strlen(tmp));
548 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
549 SILC_STATUS_ERR_NO_SUCH_NICK,
550 3, tmp, strlen(tmp));
555 /* Send IDENTIFY reply */
556 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
557 tmp = silc_command_get_first_arg(cmd->payload, NULL);
558 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
562 3, nick, strlen(nick));
564 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
565 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
566 silc_server_packet_send_dest(cmd->server, cmd->sock,
567 SILC_PACKET_COMMAND_REPLY, 0,
568 id, cmd->packet->src_id_type,
569 packet->data, packet->len, FALSE);
573 silc_server_packet_send(cmd->server, cmd->sock,
574 SILC_PACKET_COMMAND_REPLY, 0,
575 packet->data, packet->len, FALSE);
577 silc_free(id_string);
578 silc_buffer_free(packet);
585 silc_server_command_free(cmd);
588 /* Checks string for bad characters and returns TRUE if they are found. */
590 static int silc_server_command_bad_chars(char *nick)
592 if (strchr(nick, '\\')) return TRUE;
593 if (strchr(nick, '\"')) return TRUE;
594 if (strchr(nick, '´')) return TRUE;
595 if (strchr(nick, '`')) return TRUE;
596 if (strchr(nick, '\'')) return TRUE;
597 if (strchr(nick, '*')) return TRUE;
598 if (strchr(nick, '/')) return TRUE;
599 if (strchr(nick, '@')) return TRUE;
604 /* Server side of command NICK. Sets nickname for user. Setting
605 nickname causes generation of a new client ID for the client. The
606 new client ID is sent to the client after changing the nickname. */
608 SILC_SERVER_CMD_FUNC(nick)
610 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
611 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
612 SilcServer server = cmd->server;
614 SilcClientID *new_id;
618 SILC_LOG_DEBUG(("Start"));
620 #define LCC(x) server->local_list->client_cache[(x) - 32]
621 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
623 /* Check number of arguments */
624 if (silc_command_get_arg_num(cmd->payload) < 1) {
625 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
626 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
631 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
632 if (silc_server_command_bad_chars(nick) == TRUE) {
633 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
634 SILC_STATUS_ERR_BAD_NICKNAME);
638 /* Create new Client ID */
639 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
640 cmd->server->md5hash, nick,
643 /* Send notify about nickname change to our router. We send the new
644 ID and ask to replace it with the old one. */
645 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
646 silc_server_send_replace_id(server, server->id_entry->router->connection,
648 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
649 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
651 /* If we are router we have to distribute the new Client ID to all
653 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
654 silc_server_send_replace_id(server, server->id_entry->router->connection,
656 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
657 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
659 /* Remove old cache entry */
660 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
661 LCCC(id_entry->nickname[0]),
662 SILC_ID_CLIENT, id_entry->id);
666 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
667 silc_free(id_entry->id);
670 /* Save the nickname as this client is our local client */
671 if (id_entry->nickname)
672 silc_free(id_entry->nickname);
674 id_entry->nickname = strdup(nick);
675 id_entry->id = new_id;
677 /* Update client cache */
678 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
679 id_entry->nickname, SILC_ID_CLIENT,
680 id_entry->id, (void *)id_entry);
682 /* Send the new Client ID as reply command back to client */
683 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
684 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
688 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
689 0, packet->data, packet->len, FALSE);
691 silc_free(id_string);
692 silc_buffer_free(packet);
695 silc_server_command_free(cmd);
700 SILC_SERVER_CMD_FUNC(list)
704 SILC_SERVER_CMD_FUNC(topic)
708 /* Server side of INVITE command. Invites some client to join some channel. */
710 SILC_SERVER_CMD_FUNC(invite)
712 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
713 SilcServer server = cmd->server;
714 SilcSocketConnection sock = cmd->sock, dest_sock;
715 SilcClientList *sender, *dest;
716 SilcClientID *dest_id;
717 SilcChannelList *channel;
718 SilcChannelID *channel_id;
719 unsigned int argc, len;
720 unsigned char *id_string;
722 /* Check number of arguments */
723 argc = silc_command_get_arg_num(cmd->payload);
725 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
726 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
730 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
731 SILC_STATUS_ERR_TOO_MANY_PARAMS);
735 /* Get destination ID */
736 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
738 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
739 SILC_STATUS_ERR_NO_CLIENT_ID);
742 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
745 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
747 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
748 SILC_STATUS_ERR_NO_CHANNEL_ID);
751 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
753 /* Check whether the channel exists */
754 channel = silc_idlist_find_channel_by_id(server->local_list->channels,
757 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
758 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
762 /* Check whether the sender of this command is on the channel. */
763 sender = (SilcClientList *)sock->user_data;
764 if (!silc_server_client_on_channel(sender, channel)) {
765 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
766 SILC_STATUS_ERR_NOT_ON_CHANNEL);
770 /* Check whether the channel is invite-only channel. If yes then the
771 sender of this command must be at least channel operator. */
774 /* Find the connection data for the destination. If it is local we will
775 send it directly otherwise we will send it to router for routing. */
776 dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
778 dest_sock = (SilcSocketConnection)dest->connection;
780 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
782 /* Check whether the requested client is already on the channel. */
783 /* XXX if we are normal server we don't know about global clients on
784 the channel thus we must request it (NAMES command), check from
785 local cache as well. */
786 if (silc_server_client_on_channel(dest, channel)) {
787 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
788 SILC_STATUS_ERR_USER_ON_CHANNEL);
792 /* Send notify to the client that is invited to the channel */
793 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
794 "%s invites you to channel %s",
795 sender->nickname, channel->channel_name);
797 /* Send command reply */
798 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
802 silc_server_command_free(cmd);
805 /* Quits connection to client. This gets called if client won't
806 close the connection even when it has issued QUIT command. */
808 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
810 SilcServer server = (SilcServer)context;
811 SilcSocketConnection sock = server->sockets[fd];
813 /* Free all client specific data, such as client entry and entires
814 on channels this client may be on. */
815 silc_server_free_sock_user_data(server, sock);
817 /* Close the connection on our side */
818 silc_server_close_connection(server, sock);
821 /* Quits SILC session. This is the normal way to disconnect client. */
823 SILC_SERVER_CMD_FUNC(quit)
825 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
826 SilcServer server = cmd->server;
827 SilcSocketConnection sock = cmd->sock;
829 SILC_LOG_DEBUG(("Start"));
831 /* We quit the connection with little timeout */
832 silc_task_register(server->timeout_queue, sock->sock,
833 silc_server_command_quit_cb, server,
834 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
836 silc_server_command_free(cmd);
839 SILC_SERVER_CMD_FUNC(kill)
843 /* Server side of command INFO. This sends information about us to
844 the client. If client requested specific server we will send the
845 command to that server. */
847 SILC_SERVER_CMD_FUNC(info)
849 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
850 SilcServer server = cmd->server;
853 unsigned char *id_string;
854 char info_string[256], *dest_server;
856 argc = silc_command_get_arg_num(cmd->payload);
858 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
859 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
863 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
864 SILC_STATUS_ERR_TOO_MANY_PARAMS);
868 /* Get server name */
869 dest_server = silc_command_get_arg_type(cmd->payload, 1, NULL);
871 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
872 SILC_STATUS_ERR_NO_SUCH_SERVER);
876 if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
878 memset(info_string, 0, sizeof(info_string));
879 snprintf(info_string, sizeof(info_string), "%s %s %s <%s>",
880 server->config->admin_info->location,
881 server->config->admin_info->server_type,
882 server->config->admin_info->admin_name,
883 server->config->admin_info->admin_email);
885 id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
888 silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
890 2, id_string, SILC_ID_SERVER_LEN,
892 strlen(info_string));
893 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
894 packet->data, packet->len, FALSE);
896 silc_free(id_string);
897 silc_buffer_free(packet);
899 /* Send this command to the requested server */
901 if (server->server_type == SILC_SERVER && !server->standalone) {
905 if (server->server_type == SILC_ROUTER) {
911 silc_server_command_free(cmd);
914 SILC_SERVER_CMD_FUNC(connect)
918 /* Server side of command PING. This just replies to the ping. */
920 SILC_SERVER_CMD_FUNC(ping)
922 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
923 SilcServer server = cmd->server;
926 unsigned char *id_string;
928 argc = silc_command_get_arg_num(cmd->payload);
930 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
931 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
935 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
936 SILC_STATUS_ERR_TOO_MANY_PARAMS);
941 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
943 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
944 SILC_STATUS_ERR_NO_SERVER_ID);
947 id = silc_id_str2id(id_string, SILC_ID_SERVER);
949 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
951 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
954 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
955 SILC_STATUS_ERR_NO_SUCH_SERVER);
962 silc_server_command_free(cmd);
965 SILC_SERVER_CMD_FUNC(oper)
974 SilcChannelList *channel;
976 } JoinInternalContext;
978 SILC_TASK_CALLBACK(silc_server_command_join_notify)
980 JoinInternalContext *ctx = (JoinInternalContext *)context;
982 if (ctx->channel->key && ctx->channel->key_len) {
983 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
984 "%s (%s@%s) has joined channel %s",
985 ctx->nickname, ctx->username,
986 ctx->hostname, ctx->channel_name);
989 silc_task_register(ctx->server->timeout_queue, fd,
990 silc_server_command_join_notify, context,
991 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
995 /* Assembles NAMES command and executes it. This is called when client
996 joins to a channel and we wan't to send NAMES command reply to the
999 void silc_server_command_send_names(SilcServer server,
1000 SilcSocketConnection sock,
1001 SilcChannelList *channel)
1003 SilcServerCommandContext cmd;
1005 unsigned char *id_string;
1007 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1008 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
1009 1, id_string, SILC_ID_CHANNEL_LEN);
1011 cmd = silc_calloc(1, sizeof(*cmd));
1012 cmd->payload = silc_command_parse_payload(buffer);
1013 cmd->server = server;
1015 cmd->pending = FALSE;
1017 silc_server_command_names((void *)cmd);
1018 silc_free(id_string);
1022 /* Server side of command JOIN. Joins client into requested channel. If
1023 the channel does not exist it will be created. */
1025 SILC_SERVER_CMD_FUNC(join)
1027 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1028 SilcServer server = cmd->server;
1029 SilcSocketConnection sock = cmd->sock;
1030 SilcBuffer buffer = cmd->packet->buffer;
1031 int argc, i, tmp_len;
1032 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
1033 unsigned char *passphrase, mode[4];
1034 SilcChannelList *channel;
1035 SilcServerID *router_id;
1036 SilcIDCache *id_cache;
1038 SilcClientList *client;
1040 SILC_LOG_DEBUG(("Start"));
1042 #define LCC(x) server->local_list->channel_cache[(x) - 32]
1043 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
1045 /* Check number of parameters */
1046 argc = silc_command_get_arg_num(cmd->payload);
1048 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1049 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1053 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1054 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1058 /* Get channel name */
1059 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
1060 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
1061 memcpy(channel_name, tmp, tmp_len);
1062 if (silc_server_command_bad_chars(tmp) == TRUE) {
1063 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1064 SILC_STATUS_ERR_BAD_CHANNEL);
1065 silc_free(channel_name);
1069 /* Get passphrase */
1070 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
1072 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
1073 memcpy(passphrase, tmp, tmp_len);
1076 /* Get cipher name */
1077 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
1079 /* See if the channel exists */
1080 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
1081 channel_name, &id_cache) == FALSE) {
1082 /* Channel not found */
1085 /* If we are standalone server we don't have a router, we just create
1086 the channel by ourselves. */
1087 if (server->standalone) {
1088 router_id = server->id;
1089 channel = silc_server_new_channel(server, router_id,
1090 cipher, channel_name);
1094 /* No channel ID found, the channel does not exist on our server.
1095 We send JOIN command to our router which will handle the joining
1096 procedure (either creates the channel if it doesn't exist or
1097 joins the client to it) - if we are normal server. */
1098 if (server->server_type == SILC_SERVER) {
1100 /* Forward the original JOIN command to the router */
1101 silc_buffer_push(buffer, buffer->data - buffer->head);
1102 silc_server_packet_forward(server, (SilcSocketConnection)
1103 server->id_entry->router->connection,
1104 buffer->data, buffer->len, TRUE);
1106 /* Add the command to be pending. It will be re-executed after
1107 router has replied back to us. */
1108 cmd->pending = TRUE;
1109 silc_server_command_pending(SILC_COMMAND_JOIN,
1110 silc_server_command_join, context);
1115 /* If we are router and the channel does not exist we will check our
1116 global list for the channel. */
1117 if (!id_cache && server->server_type == SILC_ROUTER) {
1119 /* Notify all routers about the new channel in SILC network. */
1120 if (!server->standalone) {
1122 silc_server_send_new_id(server, server->id_entry->router->connection,
1124 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
1130 channel = (SilcChannelList *)id_cache->context;
1134 /* If the JOIN request was forwarded to us we will make a bit slower
1135 query to get the client pointer. Otherwise, we get the client pointer
1137 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1138 client = (SilcClientList *)sock->user_data;
1140 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1141 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
1149 /* Check whether the client already is on the channel */
1150 if (silc_server_client_on_channel(client, channel)) {
1151 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
1152 SILC_STATUS_ERR_USER_ON_CHANNEL);
1153 silc_free(channel_name);
1157 /* Join the client to the channel */
1158 i = channel->user_list_count;
1159 channel->user_list = silc_realloc(channel->user_list,
1160 sizeof(*channel->user_list) * (i + 1));
1161 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
1162 channel->user_list[i].client = client;
1163 channel->user_list_count++;
1165 /* Add the channel to client's channel list */
1166 i = client->channel_count;
1167 client->channel = silc_realloc(client->channel,
1168 sizeof(*client->channel) * (i + 1));
1169 client->channel[i] = channel;
1170 client->channel_count++;
1172 /* Notify router about new user on channel. If we are normal server
1173 we send it to our router, if we are router we send it to our
1175 if (!server->standalone) {
1179 /* Send command reply to the client. Client receives the Channe ID,
1180 channel mode and possibly other information in this reply packet. */
1181 if (!cmd->pending) {
1182 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1183 SILC_PUT32_MSB(channel->mode, mode);
1185 if (!channel->topic)
1187 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1190 strlen(channel_name),
1191 3, id_string, SILC_ID_CHANNEL_LEN,
1195 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1198 strlen(channel_name),
1199 3, id_string, SILC_ID_CHANNEL_LEN,
1202 strlen(channel->topic));
1204 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1205 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1206 silc_server_packet_send_dest(cmd->server, cmd->sock,
1207 SILC_PACKET_COMMAND_REPLY, 0,
1208 id, cmd->packet->src_id_type,
1209 packet->data, packet->len, FALSE);
1212 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1213 packet->data, packet->len, FALSE);
1215 silc_buffer_free(packet);
1218 /* Send channel key to the client. Client cannot start transmitting
1219 to the channel until we have sent the key. */
1220 if (!cmd->pending) {
1221 tmp_len = strlen(channel->channel_key->cipher->name);
1223 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1225 channel->channel_key->cipher->name,
1226 channel->key_len / 8, channel->key);
1228 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1229 packet->data, packet->len, FALSE);
1230 silc_buffer_free(packet);
1234 silc_free(id_string);
1236 /* Finally, send notify message to all clients on the channel about
1237 new user on the channel. */
1238 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1239 if (!cmd->pending) {
1240 silc_server_send_notify_to_channel(server, channel,
1241 "%s (%s@%s) has joined channel %s",
1242 client->nickname, client->username,
1243 sock->hostname ? sock->hostname :
1244 sock->ip, channel_name);
1246 /* This is pending command request. Send the notify after we have
1247 received the key for the channel from the router. */
1248 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1249 ctx->channel_name = channel_name;
1250 ctx->nickname = client->nickname;
1251 ctx->username = client->username;
1252 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1253 ctx->channel = channel;
1254 ctx->server = server;
1255 silc_task_register(server->timeout_queue, sock->sock,
1256 silc_server_command_join_notify, ctx,
1257 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1261 /* Send NAMES command reply to the joined channel so the user sees who
1262 is currently on the channel. */
1263 silc_server_command_send_names(server, sock, channel);
1266 silc_server_command_free(cmd);
1271 /* Server side of command MOTD. Sends servers current "message of the
1272 day" to the client. */
1274 SILC_SERVER_CMD_FUNC(motd)
1277 SILC_LOG_DEBUG(("Start"));
1281 SILC_SERVER_CMD_FUNC(umode)
1285 SILC_SERVER_CMD_FUNC(cmode)
1289 SILC_SERVER_CMD_FUNC(kick)
1293 SILC_SERVER_CMD_FUNC(restart)
1297 SILC_SERVER_CMD_FUNC(close)
1301 SILC_SERVER_CMD_FUNC(die)
1305 SILC_SERVER_CMD_FUNC(silcoper)
1309 /* Server side command of LEAVE. Removes client from a channel. */
1311 SILC_SERVER_CMD_FUNC(leave)
1313 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1314 SilcServer server = cmd->server;
1315 SilcSocketConnection sock = cmd->sock;
1316 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1318 SilcChannelList *channel;
1320 unsigned int i, argc, key_len;
1321 unsigned char *tmp, channel_key[32];
1323 SILC_LOG_DEBUG(("Start"));
1325 argc = silc_command_get_arg_num(cmd->payload);
1327 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1328 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1332 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1333 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1337 /* Get Channel ID */
1338 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1340 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1341 SILC_STATUS_ERR_NO_CHANNEL_ID);
1344 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1346 /* Get channel entry */
1347 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1349 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1350 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1354 /* Check whether this client is on the channel */
1355 if (!silc_server_client_on_channel(id_entry, channel)) {
1356 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1357 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1361 /* Remove client from channel */
1362 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1363 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1366 /* If the channel does not exist anymore we won't send anything */
1370 /* Re-generate channel key */
1371 key_len = channel->key_len / 8;
1372 for (i = 0; i < key_len; i++)
1373 channel_key[i] = silc_rng_get_byte(server->rng);
1374 channel->channel_key->cipher->set_key(channel->channel_key->context,
1375 channel_key, key_len);
1376 memset(channel->key, 0, key_len);
1377 silc_free(channel->key);
1378 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1379 memcpy(channel->key, channel_key, key_len);
1380 memset(channel_key, 0, sizeof(channel_key));
1382 /* Encode channel key payload to be distributed on the channel */
1384 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1385 strlen(channel->channel_key->cipher->name),
1386 channel->channel_key->cipher->name,
1387 key_len, channel->key);
1389 /* If we are normal server then we will send it to our router. If we
1390 are router we will send it to all local servers that has clients on
1392 if (server->server_type == SILC_SERVER) {
1393 if (!server->standalone)
1394 silc_server_packet_send(server,
1395 cmd->server->id_entry->router->connection,
1396 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1402 /* Send to locally connected clients on the channel */
1403 silc_server_packet_send_local_channel(server, channel,
1404 SILC_PACKET_CHANNEL_KEY, 0,
1405 packet->data, packet->len, FALSE);
1407 silc_buffer_free(packet);
1411 silc_server_command_free(cmd);
1414 /* Server side of command NAMES. Resolves clients and their names currently
1415 joined on the requested channel. The name list is sent back to the
1418 SILC_SERVER_CMD_FUNC(names)
1420 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1421 SilcServer server = cmd->server;
1422 SilcChannelList *channel;
1425 unsigned int i, len, len2, argc;
1427 char *name_list = NULL, *n;
1428 SilcBuffer client_id_list;
1430 SILC_LOG_DEBUG(("Start"));
1432 argc = silc_command_get_arg_num(cmd->payload);
1434 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1435 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1439 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1440 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1444 /* Get Channel ID */
1445 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1447 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1448 SILC_STATUS_ERR_NO_CHANNEL_ID);
1451 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1453 /* Check whether the channel exists. If we are normal server and the
1454 channel does not exist we will send this same command to our router
1455 which will know if the channel exists. */
1456 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1458 if (server->server_type == SILC_SERVER && !server->standalone) {
1459 /* XXX Send names command */
1461 cmd->pending = TRUE;
1462 silc_server_command_pending(SILC_COMMAND_NAMES,
1463 silc_server_command_names, context);
1467 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1468 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1472 /* Assemble the name list now */
1475 for (i = 0; i < channel->user_list_count; i++) {
1476 if (!channel->user_list[i].client)
1479 n = channel->user_list[i].client->nickname;
1483 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1484 memcpy(name_list + (len - len2), n, len2);
1487 if (i == channel->user_list_count - 1)
1489 memcpy(name_list + len, ",", 1);
1494 /* Assemble the Client ID list now */
1495 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1496 channel->user_list_count);
1497 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1498 channel->user_list_count));
1499 for (i = 0; i < channel->user_list_count; i++) {
1500 unsigned char *id_string;
1502 if (!channel->user_list[i].client)
1505 id_string = silc_id_id2str(channel->user_list[i].client->id,
1507 silc_buffer_format(client_id_list,
1508 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1510 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1511 silc_free(id_string);
1513 silc_buffer_push(client_id_list,
1514 client_id_list->data - client_id_list->head);
1517 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1519 2, tmp, SILC_ID_CHANNEL_LEN,
1522 4, client_id_list->data,
1523 client_id_list->len);
1524 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1525 packet->data, packet->len, FALSE);
1527 silc_buffer_free(packet);
1528 silc_free(name_list);
1529 silc_buffer_free(client_id_list);
1533 silc_server_command_free(cmd);