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.5 2000/07/06 07:16:43 priikone
24 * Fixed a wrong way of sending command replies. The fixed way
25 * does comply with the protocol.
27 * Revision 1.4 2000/07/05 06:13:38 priikone
28 * Added PING, INVITE and NAMES command.
30 * Revision 1.3 2000/07/03 05:52:22 priikone
31 * Implemented LEAVE command.
33 * Revision 1.2 2000/06/28 05:06:38 priikone
34 * Shorter timeout for channel joining notify.
36 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
37 * Imported from internal CVS/Added Log headers.
42 #include "serverincludes.h"
43 #include "server_internal.h"
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(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
67 SILC_SERVER_CMD(restart, RESTART,
68 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
69 SILC_SERVER_CMD(close, CLOSE,
70 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
71 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
72 SILC_SERVER_CMD(silcoper, SILCOPER,
73 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
74 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
75 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
80 /* List of pending commands. */
81 SilcServerCommandPending *silc_command_pending = NULL;
83 /* Add new pending command to the list of pending commands. Currently
84 pending commands are executed from command replies, thus we can
85 execute any command after receiving some specific command reply.
87 The argument `reply_cmd' is the command reply from where the callback
88 function is to be called, thus, it IS NOT the command to be executed. */
90 void silc_server_command_pending(SilcCommand reply_cmd,
91 SilcCommandCb callback,
94 SilcServerCommandPending *reply, *r;
96 reply = silc_calloc(1, sizeof(*reply));
97 reply->reply_cmd = reply_cmd;
98 reply->context = context;
99 reply->callback = callback;
101 if (silc_command_pending == NULL) {
102 silc_command_pending = reply;
106 for (r = silc_command_pending; r; r = r->next) {
107 if (r->next == NULL) {
114 /* Deletes pending command by reply command type. */
116 void silc_server_command_pending_del(SilcCommand reply_cmd)
118 SilcServerCommandPending *r, *tmp;
120 if (silc_command_pending) {
121 if (silc_command_pending->reply_cmd == reply_cmd) {
122 silc_free(silc_command_pending);
123 silc_command_pending = NULL;
127 for (r = silc_command_pending; r; r = r->next) {
128 if (r->next && r->next->reply_cmd == reply_cmd) {
130 r->next = r->next->next;
138 /* Free's the command context allocated before executing the command */
140 static void silc_server_command_free(SilcServerCommandContext cmd)
143 silc_command_free_payload(cmd->payload);
148 #define SILC_COMMAND_STATUS_DATA(x) \
151 /* Sends simple status message as command reply packet */
154 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
156 SilcCommandStatus status)
160 SILC_LOG_DEBUG(("Sending command status %d", status));
162 buffer = silc_command_encode_reply_payload_va(command, status, 0);
163 silc_server_packet_send(cmd->server, cmd->sock,
164 SILC_PACKET_COMMAND_REPLY, 0,
165 buffer->data, buffer->len, FALSE);
166 silc_buffer_free(buffer);
169 /* Sends command status reply with one extra argument. The argument
170 type must be sent as argument. */
173 silc_server_command_send_status_data(SilcServerCommandContext cmd,
175 SilcCommandStatus status,
176 unsigned int arg_type,
178 unsigned int arg_len)
182 SILC_LOG_DEBUG(("Sending command status %d", status));
184 buffer = silc_command_encode_reply_payload_va(command, status, 1,
185 arg_type, arg, arg_len);
186 silc_server_packet_send(cmd->server, cmd->sock,
187 SILC_PACKET_COMMAND_REPLY, 0,
188 buffer->data, buffer->len, FALSE);
189 silc_buffer_free(buffer);
192 /* Server side of command WHOIS. Processes user's query and sends found
193 results as command replies back to the client. */
195 SILC_SERVER_CMD_FUNC(whois)
197 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
198 char *tmp, *nick = NULL, *server = NULL;
199 unsigned int argc, count = 0, len;
200 SilcClientList *entry;
202 unsigned char *id_string;
204 SILC_LOG_DEBUG(("Start"));
206 argc = silc_command_get_arg_num(cmd->payload);
208 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
209 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
213 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
214 SILC_STATUS_ERR_TOO_MANY_PARAMS);
218 /* Get the nickname@server string and parse it. */
219 tmp = silc_command_get_first_arg(cmd->payload, NULL);
221 if (strchr(tmp, '@')) {
222 len = strcspn(tmp, "@");
223 nick = silc_calloc(len + 1, sizeof(char));
224 memcpy(nick, tmp, len);
225 server = silc_calloc(strlen(tmp) - len, sizeof(char));
226 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
231 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
232 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
236 /* Get the max count of reply messages allowed */
238 tmp = silc_command_get_next_arg(cmd->payload, NULL);
240 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
241 SILC_STATUS_ERR_TOO_MANY_PARAMS);
251 /* Then, make the query from our local client list */
252 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
256 /* If we are normal server and are connected to a router we will
257 make global query from the router. */
258 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
263 /* If we are router then we will check our global list as well. */
264 if (cmd->server->server_type == SILC_ROUTER) {
266 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
269 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
270 SILC_STATUS_ERR_NO_SUCH_NICK,
271 3, tmp, strlen(tmp));
277 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
278 SILC_STATUS_ERR_NO_SUCH_NICK,
279 3, tmp, strlen(tmp));
284 /* XXX, works only for local server info */
286 /* Send WHOIS reply */
287 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
288 tmp = silc_command_get_first_arg(cmd->payload, NULL);
291 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
292 char nh[256], uh[256];
293 SilcSocketConnection hsock;
295 memset(uh, 0, sizeof(uh));
296 memset(nh, 0, sizeof(nh));
298 strncat(nh, entry->nickname, strlen(entry->nickname));
300 len = entry->router ? strlen(entry->router->server_name) :
301 strlen(cmd->server->server_name);
302 strncat(nh, entry->router ? entry->router->server_name :
303 cmd->server->server_name, len);
305 strncat(uh, entry->username, strlen(entry->username));
307 hsock = (SilcSocketConnection)entry->connection;
308 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
309 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
314 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
316 2, id_string, SILC_ID_CLIENT_LEN,
320 strlen(entry->userinfo));
323 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
325 2, id_string, SILC_ID_CLIENT_LEN,
332 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
334 2, id_string, SILC_ID_CLIENT_LEN,
336 strlen(entry->nickname),
337 4, tmp, strlen(tmp)); /* XXX */
339 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
340 0, packet->data, packet->len, FALSE);
342 silc_free(id_string);
343 silc_buffer_free(packet);
346 silc_server_command_free(cmd);
349 SILC_SERVER_CMD_FUNC(whowas)
353 SILC_SERVER_CMD_FUNC(identify)
355 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
356 char *tmp, *nick = NULL, *server = NULL;
357 unsigned int argc, count = 0, len;
358 SilcClientList *entry; SilcBuffer packet;
359 unsigned char *id_string;
361 SILC_LOG_DEBUG(("Start"));
363 argc = silc_command_get_arg_num(cmd->payload);
365 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
366 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
370 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
371 SILC_STATUS_ERR_TOO_MANY_PARAMS);
375 /* Get the nickname@server string and parse it. */
376 tmp = silc_command_get_first_arg(cmd->payload, NULL);
378 if (strchr(tmp, '@')) {
379 len = strcspn(tmp, "@");
380 nick = silc_calloc(len + 1, sizeof(char));
381 memcpy(nick, tmp, len);
382 server = silc_calloc(strlen(tmp) - len, sizeof(char));
383 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
388 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
389 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
393 /* Get the max count of reply messages allowed */
395 tmp = silc_command_get_next_arg(cmd->payload, NULL);
397 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
398 SILC_STATUS_ERR_TOO_MANY_PARAMS);
404 /* Then, make the query from our local client list */
405 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
406 nick, cmd->server->md5hash);
409 /* If we are normal server and are connected to a router we will
410 make global query from the router. */
411 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
412 SilcBuffer buffer = cmd->packet->buffer;
414 /* Send IDENTIFY command to our router */
415 silc_buffer_push(buffer, buffer->data - buffer->head);
416 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
417 cmd->server->id_entry->router->connection,
418 buffer->data, buffer->len, TRUE);
422 /* If we are router then we will check our global list as well. */
423 if (cmd->server->server_type == SILC_ROUTER) {
425 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
426 nick, cmd->server->md5hash);
428 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
429 SILC_STATUS_ERR_NO_SUCH_NICK,
430 3, tmp, strlen(tmp));
436 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
437 SILC_STATUS_ERR_NO_SUCH_NICK,
438 3, tmp, strlen(tmp));
443 /* Send IDENTIFY reply */
444 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
445 tmp = silc_command_get_first_arg(cmd->payload, NULL);
446 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
450 3, nick, strlen(nick));
452 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
453 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
454 silc_server_packet_send_dest(cmd->server, cmd->sock,
455 SILC_PACKET_COMMAND_REPLY, 0,
456 id, cmd->packet->src_id_type,
457 packet->data, packet->len, FALSE);
461 silc_server_packet_send(cmd->server, cmd->sock,
462 SILC_PACKET_COMMAND_REPLY, 0,
463 packet->data, packet->len, FALSE);
465 silc_free(id_string);
466 silc_buffer_free(packet);
473 silc_server_command_free(cmd);
476 /* Checks string for bad characters and returns TRUE if they are found. */
478 static int silc_server_command_bad_chars(char *nick)
480 if (strchr(nick, '\\')) return TRUE;
481 if (strchr(nick, '\"')) return TRUE;
482 if (strchr(nick, '´')) return TRUE;
483 if (strchr(nick, '`')) return TRUE;
484 if (strchr(nick, '\'')) return TRUE;
485 if (strchr(nick, '*')) return TRUE;
486 if (strchr(nick, '/')) return TRUE;
487 if (strchr(nick, '@')) return TRUE;
492 /* Server side of command NICK. Sets nickname for user. Setting
493 nickname causes generation of a new client ID for the client. The
494 new client ID is sent to the client after changing the nickname. */
496 SILC_SERVER_CMD_FUNC(nick)
498 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
499 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
500 SilcServer server = cmd->server;
502 SilcClientID *new_id;
506 SILC_LOG_DEBUG(("Start"));
508 #define LCC(x) server->local_list->client_cache[(x) - 32]
509 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
511 /* Check number of arguments */
512 if (silc_command_get_arg_num(cmd->payload) < 1) {
513 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
514 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
519 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
520 if (silc_server_command_bad_chars(nick) == TRUE) {
521 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
522 SILC_STATUS_ERR_BAD_NICKNAME);
526 /* Create new Client ID */
527 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
528 cmd->server->md5hash, nick,
531 /* Send notify about nickname change to our router. We send the new
532 ID and ask to replace it with the old one. */
533 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
534 silc_server_send_replace_id(server, server->id_entry->router->connection,
536 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
537 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
539 /* If we are router we have to distribute the new Client ID to all
541 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
542 silc_server_send_replace_id(server, server->id_entry->router->connection,
544 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
545 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
547 /* Remove old cache entry */
548 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
549 LCCC(id_entry->nickname[0]),
550 SILC_ID_CLIENT, id_entry->id);
554 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
555 silc_free(id_entry->id);
558 /* Save the nickname as this client is our local client */
559 if (id_entry->nickname)
560 silc_free(id_entry->nickname);
562 id_entry->nickname = strdup(nick);
563 id_entry->id = new_id;
565 /* Update client cache */
566 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
567 id_entry->nickname, SILC_ID_CLIENT,
568 id_entry->id, (void *)id_entry);
570 /* Send the new Client ID as reply command back to client */
571 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
572 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
576 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
577 0, packet->data, packet->len, FALSE);
579 silc_free(id_string);
580 silc_buffer_free(packet);
583 silc_server_command_free(cmd);
588 SILC_SERVER_CMD_FUNC(list)
592 SILC_SERVER_CMD_FUNC(topic)
596 /* Server side of INVITE command. Invites some client to join some channel. */
598 SILC_SERVER_CMD_FUNC(invite)
600 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
601 SilcServer server = cmd->server;
602 SilcSocketConnection sock = cmd->sock, dest_sock;
603 SilcClientList *sender, *dest;
604 SilcClientID *dest_id;
605 SilcChannelList *channel;
606 SilcChannelID *channel_id;
607 unsigned int argc, len;
608 unsigned char *id_string;
610 /* Check number of arguments */
611 argc = silc_command_get_arg_num(cmd->payload);
613 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
614 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
618 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
619 SILC_STATUS_ERR_TOO_MANY_PARAMS);
623 /* Get destination ID */
624 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
626 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
627 SILC_STATUS_ERR_NO_CLIENT_ID);
630 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
633 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
635 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
636 SILC_STATUS_ERR_NO_CHANNEL_ID);
639 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
641 /* Check whether the channel exists */
642 channel = silc_idlist_find_channel_by_id(server->local_list->channels,
645 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
646 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
650 /* Check whether the sender of this command is on the channel. */
651 sender = (SilcClientList *)sock->user_data;
652 if (!silc_server_client_on_channel(sender, channel)) {
653 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
654 SILC_STATUS_ERR_NOT_ON_CHANNEL);
658 /* Check whether the channel is invite-only channel. If yes then the
659 sender of this command must be at least channel operator. */
662 /* Check whether the requested client is already on the channel. */
663 /* XXX if we are normal server we don't know about global clients on
664 the channel thus we must request it (NAMES command), check from
665 local cache as well. */
667 /* Find the connection data for the destination. If it is local we will
668 send it directly otherwise we will send it to router for routing. */
669 dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
671 dest_sock = (SilcSocketConnection)dest->connection;
673 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
675 /* Send notify to the client that is invited to the channel */
676 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
677 "%s invites you to channel %s",
678 sender->nickname, channel->channel_name);
680 /* Send command reply */
681 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
685 silc_server_command_free(cmd);
688 /* Quits connection to client. This gets called if client won't
689 close the connection even when it has issued QUIT command. */
691 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
693 SilcServer server = (SilcServer)context;
694 SilcSocketConnection sock = server->sockets[fd];
696 /* Free all client specific data, such as client entry and entires
697 on channels this client may be on. */
698 silc_server_free_sock_user_data(server, sock);
700 /* Close the connection on our side */
701 silc_server_close_connection(server, sock);
704 /* Quits SILC session. This is the normal way to disconnect client. */
706 SILC_SERVER_CMD_FUNC(quit)
708 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
709 SilcServer server = cmd->server;
710 SilcSocketConnection sock = cmd->sock;
712 SILC_LOG_DEBUG(("Start"));
714 /* We quit the connection with little timeout */
715 silc_task_register(server->timeout_queue, sock->sock,
716 silc_server_command_quit_cb, server,
717 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
719 silc_server_command_free(cmd);
722 SILC_SERVER_CMD_FUNC(kill)
726 SILC_SERVER_CMD_FUNC(info)
730 SILC_SERVER_CMD_FUNC(connect)
734 /* Server side of command PING. This just replies to the ping. */
736 SILC_SERVER_CMD_FUNC(ping)
738 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
739 SilcServer server = cmd->server;
742 unsigned char *id_string;
744 argc = silc_command_get_arg_num(cmd->payload);
746 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
747 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
751 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
752 SILC_STATUS_ERR_TOO_MANY_PARAMS);
757 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
759 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
760 SILC_STATUS_ERR_NO_SERVER_ID);
763 id = silc_id_str2id(id_string, SILC_ID_SERVER);
765 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
767 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
770 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
771 SILC_STATUS_ERR_NO_SUCH_SERVER);
778 silc_server_command_free(cmd);
781 SILC_SERVER_CMD_FUNC(oper)
790 SilcChannelList *channel;
792 } JoinInternalContext;
794 SILC_TASK_CALLBACK(silc_server_command_join_notify)
796 JoinInternalContext *ctx = (JoinInternalContext *)context;
798 if (ctx->channel->key && ctx->channel->key_len) {
799 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
800 "%s (%s@%s) has joined channel %s",
801 ctx->nickname, ctx->username,
802 ctx->hostname, ctx->channel_name);
805 silc_task_register(ctx->server->timeout_queue, fd,
806 silc_server_command_join_notify, context,
807 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
811 /* Assembles NAMES command and executes it. This is called when client
812 joins to a channel and we wan't to send NAMES command reply to the
815 void silc_server_command_send_names(SilcServer server,
816 SilcSocketConnection sock,
817 SilcChannelList *channel)
819 SilcServerCommandContext cmd;
821 unsigned char *id_string;
823 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
824 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
825 1, id_string, SILC_ID_CHANNEL_LEN);
827 cmd = silc_calloc(1, sizeof(*cmd));
828 cmd->payload = silc_command_parse_payload(buffer);
829 cmd->server = server;
831 cmd->pending = FALSE;
833 silc_server_command_names((void *)cmd);
834 silc_free(id_string);
838 /* Server side of command JOIN. Joins client into requested channel. If
839 the channel does not exist it will be created. */
841 SILC_SERVER_CMD_FUNC(join)
843 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
844 SilcServer server = cmd->server;
845 SilcSocketConnection sock = cmd->sock;
846 SilcBuffer buffer = cmd->packet->buffer;
847 int argc, i, tmp_len;
848 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
849 unsigned char *passphrase, mode[4];
850 SilcChannelList *channel;
851 SilcServerID *router_id;
852 SilcIDCache *id_cache;
854 SilcClientList *client;
856 SILC_LOG_DEBUG(("Start"));
858 #define LCC(x) server->local_list->channel_cache[(x) - 32]
859 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
861 /* Check number of parameters */
862 argc = silc_command_get_arg_num(cmd->payload);
864 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
865 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
869 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
870 SILC_STATUS_ERR_TOO_MANY_PARAMS);
874 /* Get channel name */
875 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
876 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
877 memcpy(channel_name, tmp, tmp_len);
878 if (silc_server_command_bad_chars(tmp) == TRUE) {
879 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
880 SILC_STATUS_ERR_BAD_CHANNEL);
881 silc_free(channel_name);
886 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
888 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
889 memcpy(passphrase, tmp, tmp_len);
892 /* Get cipher name */
893 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
895 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
896 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
900 /* See if the channel exists */
901 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
902 channel_name, &id_cache) == FALSE) {
903 /* Channel not found */
906 /* If we are standalone server we don't have a router, we just create
907 the channel by ourselves. */
908 if (server->standalone) {
909 router_id = server->id;
910 channel = silc_server_new_channel(server, router_id,
911 cipher, channel_name);
915 /* No channel ID found, the channel does not exist on our server.
916 We send JOIN command to our router which will handle the joining
917 procedure (either creates the channel if it doesn't exist or
918 joins the client to it) - if we are normal server. */
919 if (server->server_type == SILC_SERVER) {
921 /* Forward the original JOIN command to the router */
922 silc_buffer_push(buffer, buffer->data - buffer->head);
923 silc_server_packet_forward(server, (SilcSocketConnection)
924 server->id_entry->router->connection,
925 buffer->data, buffer->len, TRUE);
927 /* Add the command to be pending. It will be re-executed after
928 router has replied back to us. */
930 silc_server_command_pending(SILC_COMMAND_JOIN,
931 silc_server_command_join, context);
936 /* If we are router and the channel does not exist we will check our
937 global list for the channel. */
938 if (!id_cache && server->server_type == SILC_ROUTER) {
940 /* Notify all routers about the new channel in SILC network. */
941 if (!server->standalone) {
943 silc_server_send_new_id(server, server->id_entry->router->connection,
945 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
951 channel = (SilcChannelList *)id_cache->context;
955 /* XXX must check whether the client already is on the channel */
957 /* Join the client to the channel */
958 i = channel->user_list_count;
959 channel->user_list = silc_realloc(channel->user_list,
960 sizeof(*channel->user_list) * (i + 1));
961 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
963 /* If the JOIN request was forwarded to us we will make a bit slower
964 query to get the client pointer. Otherwise, we get the client pointer
966 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
967 client = (SilcClientList *)sock->user_data;
968 channel->user_list[i].client = client;
970 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
971 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
972 channel->user_list[i].client = client;
975 channel->user_list_count++;
977 i = client->channel_count;
978 client->channel = silc_realloc(client->channel,
979 sizeof(*client->channel) * (i + 1));
980 client->channel[i] = channel;
981 client->channel_count++;
983 /* Notify router about new user on channel. If we are normal server
984 we send it to our router, if we are router we send it to our
986 if (!server->standalone) {
990 /* Send command reply to the client. Client receives the Channe ID,
991 channel mode and possibly other information in this reply packet. */
993 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
994 SILC_PUT32_MSB(channel->mode, mode);
998 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1001 strlen(channel_name),
1002 3, id_string, SILC_ID_CHANNEL_LEN,
1006 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1009 strlen(channel_name),
1010 3, id_string, SILC_ID_CHANNEL_LEN,
1013 strlen(channel->topic));
1015 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1016 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1017 silc_server_packet_send_dest(cmd->server, cmd->sock,
1018 SILC_PACKET_COMMAND_REPLY, 0,
1019 id, cmd->packet->src_id_type,
1020 packet->data, packet->len, FALSE);
1023 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1024 packet->data, packet->len, FALSE);
1026 silc_buffer_free(packet);
1029 /* Send channel key to the client. Client cannot start transmitting
1030 to the channel until we have sent the key. */
1031 if (!cmd->pending) {
1032 tmp_len = strlen(channel->channel_key->cipher->name);
1034 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1036 channel->channel_key->cipher->name,
1037 channel->key_len / 8, channel->key);
1039 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1040 packet->data, packet->len, FALSE);
1041 silc_buffer_free(packet);
1045 silc_free(id_string);
1047 /* Finally, send notify message to all clients on the channel about
1048 new user on the channel. */
1049 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1050 if (!cmd->pending) {
1051 silc_server_send_notify_to_channel(server, channel,
1052 "%s (%s@%s) has joined channel %s",
1053 client->nickname, client->username,
1054 sock->hostname ? sock->hostname :
1055 sock->ip, channel_name);
1057 /* This is pending command request. Send the notify after we have
1058 received the key for the channel from the router. */
1059 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1060 ctx->channel_name = channel_name;
1061 ctx->nickname = client->nickname;
1062 ctx->username = client->username;
1063 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1064 ctx->channel = channel;
1065 ctx->server = server;
1066 silc_task_register(server->timeout_queue, sock->sock,
1067 silc_server_command_join_notify, ctx,
1068 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1072 /* Send NAMES command reply to the joined channel so the user sees who
1073 is currently on the channel. */
1074 silc_server_command_send_names(server, sock, channel);
1077 silc_server_command_free(cmd);
1082 /* Server side of command MOTD. Sends servers current "message of the
1083 day" to the client. */
1085 SILC_SERVER_CMD_FUNC(motd)
1088 SILC_LOG_DEBUG(("Start"));
1092 SILC_SERVER_CMD_FUNC(umode)
1096 SILC_SERVER_CMD_FUNC(cmode)
1100 SILC_SERVER_CMD_FUNC(kick)
1104 SILC_SERVER_CMD_FUNC(restart)
1108 SILC_SERVER_CMD_FUNC(close)
1112 SILC_SERVER_CMD_FUNC(die)
1116 SILC_SERVER_CMD_FUNC(silcoper)
1120 /* Server side command of LEAVE. Removes client from a channel. */
1122 SILC_SERVER_CMD_FUNC(leave)
1124 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1125 SilcServer server = cmd->server;
1126 SilcSocketConnection sock = cmd->sock;
1127 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1129 SilcChannelList *channel;
1131 unsigned int i, argc, key_len;
1132 unsigned char *tmp, channel_key[32];
1134 SILC_LOG_DEBUG(("Start"));
1136 argc = silc_command_get_arg_num(cmd->payload);
1138 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1139 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1143 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1144 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1148 /* Get Channel ID */
1149 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1151 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1152 SILC_STATUS_ERR_NO_CHANNEL_ID);
1155 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1157 /* Get channel entry */
1158 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1160 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1161 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1165 /* Check whether this client is on the channel */
1166 if (!silc_server_client_on_channel(id_entry, channel)) {
1167 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1168 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1172 /* Remove client from channel */
1173 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1174 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1177 /* If the channel does not exist anymore we won't send anything */
1181 /* Re-generate channel key */
1182 key_len = channel->key_len / 8;
1183 for (i = 0; i < key_len; i++)
1184 channel_key[i] = silc_rng_get_byte(server->rng);
1185 channel->channel_key->cipher->set_key(channel->channel_key->context,
1186 channel_key, key_len);
1187 memset(channel->key, 0, key_len);
1188 silc_free(channel->key);
1189 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1190 memcpy(channel->key, channel_key, key_len);
1191 memset(channel_key, 0, sizeof(channel_key));
1193 /* Encode channel key payload to be distributed on the channel */
1195 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1196 strlen(channel->channel_key->cipher->name),
1197 channel->channel_key->cipher->name,
1198 key_len, channel->key);
1200 /* If we are normal server then we will send it to our router. If we
1201 are router we will send it to all local servers that has clients on
1203 if (server->server_type == SILC_SERVER) {
1204 if (!server->standalone)
1205 silc_server_packet_send(server,
1206 cmd->server->id_entry->router->connection,
1207 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1213 /* Send to locally connected clients on the channel */
1214 silc_server_packet_send_local_channel(server, channel,
1215 SILC_PACKET_CHANNEL_KEY, 0,
1216 packet->data, packet->len, FALSE);
1218 silc_buffer_free(packet);
1222 silc_server_command_free(cmd);
1225 /* Server side of command NAMES. Resolves clients and their names currently
1226 joined on the requested channel. The name list is sent back to the
1229 SILC_SERVER_CMD_FUNC(names)
1231 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1232 SilcServer server = cmd->server;
1233 SilcChannelList *channel;
1236 unsigned int i, len, len2, argc;
1238 char *name_list = NULL, *n;
1239 SilcBuffer client_id_list;
1241 SILC_LOG_DEBUG(("Start"));
1243 argc = silc_command_get_arg_num(cmd->payload);
1245 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1246 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1250 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1251 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1255 /* Get Channel ID */
1256 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1258 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1259 SILC_STATUS_ERR_NO_CHANNEL_ID);
1262 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1264 /* Check whether the channel exists. If we are normal server and the
1265 channel does not exist we will send this same command to our router
1266 which will know if the channel exists. */
1267 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1269 if (server->server_type == SILC_SERVER && !server->standalone) {
1270 /* XXX Send names command */
1272 cmd->pending = TRUE;
1273 silc_server_command_pending(SILC_COMMAND_NAMES,
1274 silc_server_command_names, context);
1278 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1279 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1283 /* Assemble the name list now */
1286 for (i = 0; i < channel->user_list_count; i++) {
1287 if (!channel->user_list[i].client)
1290 n = channel->user_list[i].client->nickname;
1294 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1295 memcpy(name_list + (len - len2), n, len2);
1298 if (i == channel->user_list_count - 1)
1300 memcpy(name_list + len, ",", 1);
1305 /* Assemble the Client ID list now */
1306 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1307 channel->user_list_count);
1308 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1309 channel->user_list_count));
1310 for (i = 0; i < channel->user_list_count; i++) {
1311 unsigned char *id_string;
1313 if (!channel->user_list[i].client)
1316 id_string = silc_id_id2str(channel->user_list[i].client->id,
1318 silc_buffer_format(client_id_list,
1319 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1321 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1322 silc_free(id_string);
1324 silc_buffer_push(client_id_list,
1325 client_id_list->data - client_id_list->head);
1328 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1330 2, tmp, SILC_ID_CHANNEL_LEN,
1333 4, client_id_list->data,
1334 client_id_list->len);
1335 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1336 packet->data, packet->len, FALSE);
1338 silc_buffer_free(packet);
1339 silc_free(name_list);
1340 silc_buffer_free(client_id_list);
1344 silc_server_command_free(cmd);