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.2 2000/06/28 05:06:38 priikone
24 * Shorter timeout for channel joining notify.
26 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
27 * Importet from internal CVS/Added Log headers.
32 #include "serverincludes.h"
33 #include "server_internal.h"
35 /* Server command list. */
36 SilcServerCommand silc_command_list[] =
38 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
39 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
40 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
41 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
42 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
43 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
44 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
45 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
46 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
47 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
48 SILC_SERVER_CMD(connect, CONNECT,
49 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
50 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
52 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
53 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
55 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
56 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
57 SILC_SERVER_CMD(restart, RESTART,
58 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
59 SILC_SERVER_CMD(close, CLOSE,
60 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
61 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62 SILC_SERVER_CMD(silcoper, SILCOPER,
63 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
64 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
65 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
70 /* List of pending commands. */
71 SilcServerCommandPending *silc_command_pending = NULL;
73 /* Add new pending command to the list of pending commands. Currently
74 pending commands are executed from command replies, thus we can
75 execute any command after receiving some specific command reply.
77 The argument `reply_cmd' is the command reply from where the callback
78 function is to be called, thus, it IS NOT the command to be executed. */
80 void silc_server_command_pending(SilcCommand reply_cmd,
81 SilcCommandCb callback,
84 SilcServerCommandPending *reply, *r;
86 reply = silc_calloc(1, sizeof(*reply));
87 reply->reply_cmd = reply_cmd;
88 reply->context = context;
89 reply->callback = callback;
91 if (silc_command_pending == NULL) {
92 silc_command_pending = reply;
96 for (r = silc_command_pending; r; r = r->next) {
97 if (r->next == NULL) {
104 /* Deletes pending command by reply command type. */
106 void silc_server_command_pending_del(SilcCommand reply_cmd)
108 SilcServerCommandPending *r, *tmp;
110 if (silc_command_pending) {
111 if (silc_command_pending->reply_cmd == reply_cmd) {
112 silc_free(silc_command_pending);
113 silc_command_pending = NULL;
117 for (r = silc_command_pending; r; r = r->next) {
118 if (r->next && r->next->reply_cmd == reply_cmd) {
120 r->next = r->next->next;
128 /* Free's the command context allocated before executing the command */
130 static void silc_server_command_free(SilcServerCommandContext cmd)
133 silc_command_free_payload(cmd->payload);
138 /* Sends command status message as command reply packet. */
141 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
143 SilcCommandStatus status,
145 unsigned int msg_len)
147 SilcBuffer sp_buf, buffer;
149 SILC_LOG_DEBUG(("Sending command status %d", status));
151 sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
152 buffer = silc_command_encode_payload_va(command, 1,
153 sp_buf->data, sp_buf->len);
154 silc_server_packet_send(cmd->server, cmd->sock,
155 SILC_PACKET_COMMAND_REPLY, 0,
156 buffer->data, buffer->len, FALSE);
157 silc_buffer_free(buffer);
158 silc_buffer_free(sp_buf);
161 /* Sends simple status message as command reply packet */
164 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
166 SilcCommandStatus status)
168 SilcBuffer sp_buf, buffer;
170 SILC_LOG_DEBUG(("Sending command status %d", status));
172 sp_buf = silc_command_encode_status_payload(status, NULL, 0);
173 buffer = silc_command_encode_payload_va(command, 1,
174 sp_buf->data, sp_buf->len);
175 silc_server_packet_send(cmd->server, cmd->sock,
176 SILC_PACKET_COMMAND_REPLY, 0,
177 buffer->data, buffer->len, FALSE);
178 silc_buffer_free(buffer);
179 silc_buffer_free(sp_buf);
182 /* Server side of command WHOIS. Processes user's query and sends found
183 results as command replies back to the client. */
185 SILC_SERVER_CMD_FUNC(whois)
187 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
188 char *tmp, *nick = NULL, *server = NULL;
189 unsigned int argc, count = 0, len;
190 SilcClientList *entry;
191 SilcBuffer sp_buf, packet;
192 unsigned char *id_string;
194 SILC_LOG_DEBUG(("Start"));
196 argc = silc_command_get_arg_num(cmd->payload);
198 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
199 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
203 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
204 SILC_STATUS_ERR_TOO_MANY_PARAMS);
208 /* Get the nickname@server string and parse it. */
209 tmp = silc_command_get_first_arg(cmd->payload, NULL);
211 if (strchr(tmp, '@')) {
212 len = strcspn(tmp, "@");
213 nick = silc_calloc(len + 1, sizeof(char));
214 memcpy(nick, tmp, len);
215 server = silc_calloc(strlen(tmp) - len, sizeof(char));
216 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
221 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
222 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
226 /* Get the max count of reply messages allowed */
228 tmp = silc_command_get_next_arg(cmd->payload, NULL);
230 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
231 SILC_STATUS_ERR_TOO_MANY_PARAMS);
241 /* Then, make the query from our local client list */
242 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
246 /* If we are normal server and are connected to a router we will
247 make global query from the router. */
248 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
253 /* If we are router then we will check our global list as well. */
254 if (cmd->server->server_type == SILC_ROUTER) {
256 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
259 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
260 SILC_STATUS_ERR_NO_SUCH_NICK,
267 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
268 SILC_STATUS_ERR_NO_SUCH_NICK,
274 /* XXX, works only for local server info */
276 /* Send WHOIS reply */
277 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
278 tmp = silc_command_get_first_arg(cmd->payload, NULL),
279 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
282 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
283 char nh[256], uh[256];
284 SilcSocketConnection hsock;
286 memset(uh, 0, sizeof(uh));
287 memset(nh, 0, sizeof(nh));
289 strncat(nh, entry->nickname, strlen(entry->nickname));
291 len = entry->router ? strlen(entry->router->server_name) :
292 strlen(cmd->server->server_name);
293 strncat(nh, entry->router ? entry->router->server_name :
294 cmd->server->server_name, len);
296 strncat(uh, entry->username, strlen(entry->username));
298 hsock = (SilcSocketConnection)entry->connection;
299 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
300 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
305 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5,
306 sp_buf->data, sp_buf->len,
307 id_string, SILC_ID_CLIENT_LEN,
311 strlen(entry->userinfo));
314 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
315 sp_buf->data, sp_buf->len,
316 id_string, SILC_ID_CLIENT_LEN,
323 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
324 sp_buf->data, sp_buf->len,
325 id_string, SILC_ID_CLIENT_LEN,
326 entry->nickname, strlen(entry->nickname),
327 tmp, strlen(tmp)); /* XXX */
329 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
330 0, packet->data, packet->len, FALSE);
332 silc_free(id_string);
333 silc_buffer_free(packet);
337 silc_server_command_free(cmd);
340 SILC_SERVER_CMD_FUNC(whowas)
344 SILC_SERVER_CMD_FUNC(identify)
346 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
347 char *tmp, *nick = NULL, *server = NULL;
348 unsigned int argc, count = 0, len;
349 SilcClientList *entry;
350 SilcBuffer sp_buf, packet;
351 unsigned char *id_string;
353 SILC_LOG_DEBUG(("Start"));
355 argc = silc_command_get_arg_num(cmd->payload);
357 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
358 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
363 SILC_STATUS_ERR_TOO_MANY_PARAMS);
367 /* Get the nickname@server string and parse it. */
368 tmp = silc_command_get_first_arg(cmd->payload, NULL);
370 if (strchr(tmp, '@')) {
371 len = strcspn(tmp, "@");
372 nick = silc_calloc(len + 1, sizeof(char));
373 memcpy(nick, tmp, len);
374 server = silc_calloc(strlen(tmp) - len, sizeof(char));
375 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
380 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
381 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
385 /* Get the max count of reply messages allowed */
387 tmp = silc_command_get_next_arg(cmd->payload, NULL);
389 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
390 SILC_STATUS_ERR_TOO_MANY_PARAMS);
396 /* Then, make the query from our local client list */
397 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
398 nick, cmd->server->md5hash);
401 /* If we are normal server and are connected to a router we will
402 make global query from the router. */
403 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
404 SilcBuffer buffer = cmd->packet->buffer;
406 /* Forward the received IDENTIFY command to our router */
407 silc_buffer_push(buffer, buffer->data - buffer->head);
408 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
409 cmd->server->id_entry->router->connection,
410 buffer->data, buffer->len,
415 /* If we are router then we will check our global list as well. */
416 if (cmd->server->server_type == SILC_ROUTER) {
418 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
419 nick, cmd->server->md5hash);
421 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
422 SILC_STATUS_ERR_NO_SUCH_NICK,
429 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
430 SILC_STATUS_ERR_NO_SUCH_NICK,
436 /* Send IDENTIFY reply */
437 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
438 tmp = silc_command_get_first_arg(cmd->payload, NULL);
439 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
440 packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
441 sp_buf->data, sp_buf->len,
442 id_string, SILC_ID_CLIENT_LEN,
444 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
445 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
446 silc_server_packet_send_dest(cmd->server, cmd->sock,
447 SILC_PACKET_COMMAND_REPLY, 0,
448 id, cmd->packet->src_id_type,
449 packet->data, packet->len, FALSE);
452 silc_server_packet_send(cmd->server, cmd->sock,
453 SILC_PACKET_COMMAND_REPLY, 0,
454 packet->data, packet->len, FALSE);
456 silc_free(id_string);
457 silc_buffer_free(packet);
465 silc_server_command_free(cmd);
468 /* Checks string for bad characters and returns TRUE if they are found. */
470 static int silc_server_command_bad_chars(char *nick)
472 if (strchr(nick, '\\')) return TRUE;
473 if (strchr(nick, '\"')) return TRUE;
474 if (strchr(nick, '´')) return TRUE;
475 if (strchr(nick, '`')) return TRUE;
476 if (strchr(nick, '\'')) return TRUE;
477 if (strchr(nick, '*')) return TRUE;
478 if (strchr(nick, '/')) return TRUE;
479 if (strchr(nick, '@')) return TRUE;
484 /* Server side of command NICK. Sets nickname for user. Setting
485 nickname causes generation of a new client ID for the client. The
486 new client ID is sent to the client after changing the nickname. */
488 SILC_SERVER_CMD_FUNC(nick)
490 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
491 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
492 SilcServer server = cmd->server;
493 SilcBuffer packet, sp_buf;
494 SilcClientID *new_id;
498 SILC_LOG_DEBUG(("Start"));
500 #define LCC(x) server->local_list->client_cache[(x) - 32]
501 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
503 /* Check number of arguments */
504 if (silc_command_get_arg_num(cmd->payload) < 1) {
505 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
506 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
511 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
512 if (silc_server_command_bad_chars(nick) == TRUE) {
513 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
514 SILC_STATUS_ERR_BAD_NICKNAME);
518 /* Create new Client ID */
519 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
520 cmd->server->md5hash, nick,
523 /* Send notify about nickname change to our router. We send the new
524 ID and ask to replace it with the old one. */
525 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
526 silc_server_send_replace_id(server, server->id_entry->router->connection,
528 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
529 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
531 /* If we are router we have to distribute the new Client ID to all
533 if (cmd->server->server_type == SILC_ROUTER && !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 /* Remove old cache entry */
540 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
541 LCCC(id_entry->nickname[0]),
542 SILC_ID_CLIENT, id_entry->id);
546 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
547 silc_free(id_entry->id);
550 /* Save the nickname as this client is our local client */
551 if (id_entry->nickname)
552 silc_free(id_entry->nickname);
554 id_entry->nickname = strdup(nick);
555 id_entry->id = new_id;
557 /* Update client cache */
558 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
559 id_entry->nickname, SILC_ID_CLIENT,
560 id_entry->id, (void *)id_entry);
562 /* Send the new Client ID as reply command back to client */
563 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
564 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
565 packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
566 sp_buf->data, sp_buf->len,
567 id_string, SILC_ID_CLIENT_LEN);
568 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
569 0, packet->data, packet->len, FALSE);
571 silc_free(id_string);
572 silc_buffer_free(packet);
576 silc_server_command_free(cmd);
581 SILC_SERVER_CMD_FUNC(list)
585 SILC_SERVER_CMD_FUNC(topic)
589 SILC_SERVER_CMD_FUNC(invite)
593 /* Quits connection to client. This gets called if client won't
594 close the connection even when it has issued QUIT command. */
596 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
598 SilcServer server = (SilcServer)context;
599 SilcSocketConnection sock = server->sockets[fd];
601 /* Free all client specific data, such as client entry and entires
602 on channels this client may be on. */
603 silc_server_free_sock_user_data(server, sock);
605 /* Close the connection on our side */
606 silc_server_close_connection(server, sock);
609 /* Quits SILC session. This is the normal way to disconnect client. */
611 SILC_SERVER_CMD_FUNC(quit)
613 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
614 SilcServer server = cmd->server;
615 SilcSocketConnection sock = cmd->sock;
617 SILC_LOG_DEBUG(("Start"));
619 /* We quit the connection with little timeout */
620 silc_task_register(server->timeout_queue, sock->sock,
621 silc_server_command_quit_cb, server,
622 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
624 silc_server_command_free(cmd);
627 SILC_SERVER_CMD_FUNC(kill)
631 SILC_SERVER_CMD_FUNC(info)
635 SILC_SERVER_CMD_FUNC(connect)
639 SILC_SERVER_CMD_FUNC(ping)
643 SILC_SERVER_CMD_FUNC(oper)
652 SilcChannelList *channel;
654 } JoinInternalContext;
656 SILC_TASK_CALLBACK(silc_server_command_join_notify)
658 JoinInternalContext *ctx = (JoinInternalContext *)context;
660 if (ctx->channel->key && ctx->channel->key_len) {
661 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
662 "%s (%s@%s) has joined channel %s",
663 ctx->nickname, ctx->username,
664 ctx->hostname, ctx->channel_name);
667 silc_task_register(ctx->server->timeout_queue, fd,
668 silc_server_command_join_notify, context,
669 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
673 /* Server side of command JOIN. Joins client into requested channel. If
674 the channel does not exist it will be created. */
676 SILC_SERVER_CMD_FUNC(join)
678 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
679 SilcServer server = cmd->server;
680 SilcSocketConnection sock = cmd->sock;
681 SilcBuffer buffer = cmd->packet->buffer;
682 int argc, i, tmp_len;
683 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
684 unsigned char *passphrase;
685 SilcChannelList *channel;
686 SilcServerID *router_id;
687 SilcIDCache *id_cache;
688 SilcBuffer packet, sp_buf;
689 SilcClientList *client;
691 SILC_LOG_DEBUG(("Start"));
693 #define LCC(x) server->local_list->channel_cache[(x) - 32]
694 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
696 /* Check number of parameters */
697 argc = silc_command_get_arg_num(cmd->payload);
699 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
700 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
704 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
705 SILC_STATUS_ERR_TOO_MANY_PARAMS);
709 /* Get channel name */
710 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
711 if (silc_server_command_bad_chars(tmp) == TRUE) {
712 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
713 SILC_STATUS_ERR_BAD_CHANNEL);
716 channel_name = strdup(tmp);
719 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
721 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
722 memcpy(passphrase, tmp, tmp_len);
725 /* Get cipher name */
726 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
728 /* See if the channel exists */
729 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
730 channel_name, &id_cache) == FALSE) {
731 /* Channel not found */
734 /* If we are standalone server we don't have a router, we just create
735 the channel by ourselves. */
736 if (server->standalone) {
737 router_id = server->id;
738 channel = silc_server_new_channel(server, router_id,
739 cipher, channel_name);
743 /* No channel ID found, the channel does not exist on our server.
744 We send JOIN command to our router which will handle the joining
745 procedure (either creates the channel if it doesn't exist or
746 joins the client to it) - if we are normal server. */
747 if (server->server_type == SILC_SERVER) {
749 /* Forward the received JOIN command to the router */
750 silc_buffer_push(buffer, buffer->data - buffer->head);
751 silc_server_packet_forward(server, (SilcSocketConnection)
752 server->id_entry->router->connection,
753 buffer->data, buffer->len,
756 /* Add the command to be pending. It will be re-executed after
757 router has replied back to us. */
759 silc_server_command_pending(SILC_COMMAND_JOIN,
760 silc_server_command_join, context);
765 /* If we are router and the channel does not exist we will check our
766 global list for the channel. */
767 if (!id_cache && server->server_type == SILC_ROUTER) {
769 /* Notify all routers about the new channel in SILC network. */
770 if (!server->standalone) {
772 silc_server_send_new_id(server, server->id_entry->router->connection,
774 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
780 channel = (SilcChannelList *)id_cache->context;
784 /* XXX must check whether the client already is on the channel */
786 /* Join the client to the channel */
787 i = channel->user_list_count;
788 channel->user_list = silc_realloc(channel->user_list,
789 sizeof(*channel->user_list) * (i + 1));
790 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
792 /* If the JOIN request was forwarded to us we will make a bit slower
793 query to get the client pointer. Otherwise, we get the client pointer
795 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
796 client = (SilcClientList *)sock->user_data;
797 channel->user_list[i].client = client;
799 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
800 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
801 channel->user_list[i].client = client;
804 channel->user_list_count++;
806 i = client->channel_count;
807 client->channel = silc_realloc(client->channel,
808 sizeof(*client->channel) * (i + 1));
809 client->channel[i] = channel;
810 client->channel_count++;
812 /* Notify router about new user on channel. If we are normal server
813 we send it to our router, if we are router we send it to our
815 if (!server->standalone) {
819 /* Send Channel ID to the client */
821 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
822 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
825 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 3,
826 sp_buf->data, sp_buf->len,
827 channel_name, strlen(channel_name),
828 id_string, SILC_ID_CHANNEL_LEN);
831 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
832 sp_buf->data, sp_buf->len,
833 channel_name, strlen(channel_name),
834 id_string, SILC_ID_CHANNEL_LEN,
836 strlen(channel->topic));
838 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
839 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
840 silc_server_packet_send_dest(cmd->server, cmd->sock,
841 SILC_PACKET_COMMAND_REPLY, 0,
842 id, cmd->packet->src_id_type,
843 packet->data, packet->len, FALSE);
846 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
847 packet->data, packet->len, FALSE);
849 silc_buffer_free(packet);
853 /* Send channel key to the client. Client cannot start transmitting
854 to the channel until we have sent the key. */
856 tmp_len = strlen(channel->channel_key->cipher->name);
858 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
860 channel->channel_key->cipher->name,
861 channel->key_len, channel->key);
863 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
864 packet->data, packet->len, FALSE);
865 silc_buffer_free(packet);
869 silc_free(id_string);
871 /* Finally, send notify message to all clients on the channel about
872 new user on the channel. */
873 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
875 silc_server_send_notify_to_channel(server, channel,
876 "%s (%s@%s) has joined channel %s",
877 client->nickname, client->username,
878 sock->hostname ? sock->hostname :
879 sock->ip, channel_name);
881 /* This is pending command request. Send the notify after we have
882 received the key for the channel from the router. */
883 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
884 ctx->channel_name = channel_name;
885 ctx->nickname = client->nickname;
886 ctx->username = client->username;
887 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
888 ctx->channel = channel;
889 ctx->server = server;
890 silc_task_register(server->timeout_queue, sock->sock,
891 silc_server_command_join_notify, ctx,
892 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
897 silc_server_command_free(cmd);
902 /* Server side of command MOTD. Sends servers current "message of the
903 day" to the client. */
905 SILC_SERVER_CMD_FUNC(motd)
908 SILC_LOG_DEBUG(("Start"));
912 SILC_SERVER_CMD_FUNC(umode)
916 SILC_SERVER_CMD_FUNC(cmode)
920 SILC_SERVER_CMD_FUNC(kick)
924 SILC_SERVER_CMD_FUNC(restart)
928 SILC_SERVER_CMD_FUNC(close)
932 SILC_SERVER_CMD_FUNC(die)
936 SILC_SERVER_CMD_FUNC(silcoper)
940 SILC_SERVER_CMD_FUNC(leave)
944 SILC_SERVER_CMD_FUNC(names)