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.1 2000/06/27 11:36:56 priikone
29 #include "serverincludes.h"
30 #include "server_internal.h"
32 /* Server command list. */
33 SilcServerCommand silc_command_list[] =
35 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
36 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
37 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
38 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
39 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
40 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
41 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
42 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
43 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
44 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
45 SILC_SERVER_CMD(connect, CONNECT,
46 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
47 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
48 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
49 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
50 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
52 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
53 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(restart, RESTART,
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
56 SILC_SERVER_CMD(close, CLOSE,
57 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
58 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
59 SILC_SERVER_CMD(silcoper, SILCOPER,
60 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
61 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
62 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
67 /* List of pending commands. */
68 SilcServerCommandPending *silc_command_pending = NULL;
70 /* Add new pending command to the list of pending commands. Currently
71 pending commands are executed from command replies, thus we can
72 execute any command after receiving some specific command reply.
74 The argument `reply_cmd' is the command reply from where the callback
75 function is to be called, thus, it IS NOT the command to be executed. */
77 void silc_server_command_pending(SilcCommand reply_cmd,
78 SilcCommandCb callback,
81 SilcServerCommandPending *reply, *r;
83 reply = silc_calloc(1, sizeof(*reply));
84 reply->reply_cmd = reply_cmd;
85 reply->context = context;
86 reply->callback = callback;
88 if (silc_command_pending == NULL) {
89 silc_command_pending = reply;
93 for (r = silc_command_pending; r; r = r->next) {
94 if (r->next == NULL) {
101 /* Deletes pending command by reply command type. */
103 void silc_server_command_pending_del(SilcCommand reply_cmd)
105 SilcServerCommandPending *r, *tmp;
107 if (silc_command_pending) {
108 if (silc_command_pending->reply_cmd == reply_cmd) {
109 silc_free(silc_command_pending);
110 silc_command_pending = NULL;
114 for (r = silc_command_pending; r; r = r->next) {
115 if (r->next && r->next->reply_cmd == reply_cmd) {
117 r->next = r->next->next;
125 /* Free's the command context allocated before executing the command */
127 static void silc_server_command_free(SilcServerCommandContext cmd)
130 silc_command_free_payload(cmd->payload);
135 /* Sends command status message as command reply packet. */
138 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
140 SilcCommandStatus status,
142 unsigned int msg_len)
144 SilcBuffer sp_buf, buffer;
146 SILC_LOG_DEBUG(("Sending command status %d", status));
148 sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
149 buffer = silc_command_encode_payload_va(command, 1,
150 sp_buf->data, sp_buf->len);
151 silc_server_packet_send(cmd->server, cmd->sock,
152 SILC_PACKET_COMMAND_REPLY, 0,
153 buffer->data, buffer->len, FALSE);
154 silc_buffer_free(buffer);
155 silc_buffer_free(sp_buf);
158 /* Sends simple status message as command reply packet */
161 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
163 SilcCommandStatus status)
165 SilcBuffer sp_buf, buffer;
167 SILC_LOG_DEBUG(("Sending command status %d", status));
169 sp_buf = silc_command_encode_status_payload(status, NULL, 0);
170 buffer = silc_command_encode_payload_va(command, 1,
171 sp_buf->data, sp_buf->len);
172 silc_server_packet_send(cmd->server, cmd->sock,
173 SILC_PACKET_COMMAND_REPLY, 0,
174 buffer->data, buffer->len, FALSE);
175 silc_buffer_free(buffer);
176 silc_buffer_free(sp_buf);
179 /* Server side of command WHOIS. Processes user's query and sends found
180 results as command replies back to the client. */
182 SILC_SERVER_CMD_FUNC(whois)
184 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
185 char *tmp, *nick = NULL, *server = NULL;
186 unsigned int argc, count = 0, len;
187 SilcClientList *entry;
188 SilcBuffer sp_buf, packet;
189 unsigned char *id_string;
191 SILC_LOG_DEBUG(("Start"));
193 argc = silc_command_get_arg_num(cmd->payload);
195 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
196 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
200 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
201 SILC_STATUS_ERR_TOO_MANY_PARAMS);
205 /* Get the nickname@server string and parse it. */
206 tmp = silc_command_get_first_arg(cmd->payload, NULL);
208 if (strchr(tmp, '@')) {
209 len = strcspn(tmp, "@");
210 nick = silc_calloc(len + 1, sizeof(char));
211 memcpy(nick, tmp, len);
212 server = silc_calloc(strlen(tmp) - len, sizeof(char));
213 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
218 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
219 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
223 /* Get the max count of reply messages allowed */
225 tmp = silc_command_get_next_arg(cmd->payload, NULL);
227 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
228 SILC_STATUS_ERR_TOO_MANY_PARAMS);
238 /* Then, make the query from our local client list */
239 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
243 /* If we are normal server and are connected to a router we will
244 make global query from the router. */
245 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
250 /* If we are router then we will check our global list as well. */
251 if (cmd->server->server_type == SILC_ROUTER) {
253 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
256 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
257 SILC_STATUS_ERR_NO_SUCH_NICK,
264 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
265 SILC_STATUS_ERR_NO_SUCH_NICK,
271 /* XXX, works only for local server info */
273 /* Send WHOIS reply */
274 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
275 tmp = silc_command_get_first_arg(cmd->payload, NULL),
276 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
279 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
280 char nh[256], uh[256];
281 SilcSocketConnection hsock;
283 memset(uh, 0, sizeof(uh));
284 memset(nh, 0, sizeof(nh));
286 strncat(nh, entry->nickname, strlen(entry->nickname));
288 len = entry->router ? strlen(entry->router->server_name) :
289 strlen(cmd->server->server_name);
290 strncat(nh, entry->router ? entry->router->server_name :
291 cmd->server->server_name, len);
293 strncat(uh, entry->username, strlen(entry->username));
295 hsock = (SilcSocketConnection)entry->connection;
296 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
297 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
302 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5,
303 sp_buf->data, sp_buf->len,
304 id_string, SILC_ID_CLIENT_LEN,
308 strlen(entry->userinfo));
311 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
312 sp_buf->data, sp_buf->len,
313 id_string, SILC_ID_CLIENT_LEN,
320 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
321 sp_buf->data, sp_buf->len,
322 id_string, SILC_ID_CLIENT_LEN,
323 entry->nickname, strlen(entry->nickname),
324 tmp, strlen(tmp)); /* XXX */
326 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
327 0, packet->data, packet->len, FALSE);
329 silc_free(id_string);
330 silc_buffer_free(packet);
334 silc_server_command_free(cmd);
337 SILC_SERVER_CMD_FUNC(whowas)
341 SILC_SERVER_CMD_FUNC(identify)
343 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
344 char *tmp, *nick = NULL, *server = NULL;
345 unsigned int argc, count = 0, len;
346 SilcClientList *entry;
347 SilcBuffer sp_buf, packet;
348 unsigned char *id_string;
350 SILC_LOG_DEBUG(("Start"));
352 argc = silc_command_get_arg_num(cmd->payload);
354 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
355 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
359 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
360 SILC_STATUS_ERR_TOO_MANY_PARAMS);
364 /* Get the nickname@server string and parse it. */
365 tmp = silc_command_get_first_arg(cmd->payload, NULL);
367 if (strchr(tmp, '@')) {
368 len = strcspn(tmp, "@");
369 nick = silc_calloc(len + 1, sizeof(char));
370 memcpy(nick, tmp, len);
371 server = silc_calloc(strlen(tmp) - len, sizeof(char));
372 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
377 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
378 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
382 /* Get the max count of reply messages allowed */
384 tmp = silc_command_get_next_arg(cmd->payload, NULL);
386 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
387 SILC_STATUS_ERR_TOO_MANY_PARAMS);
393 /* Then, make the query from our local client list */
394 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
395 nick, cmd->server->md5hash);
398 /* If we are normal server and are connected to a router we will
399 make global query from the router. */
400 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
401 SilcBuffer buffer = cmd->packet->buffer;
403 /* Forward the received IDENTIFY command to our router */
404 silc_buffer_push(buffer, buffer->data - buffer->head);
405 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
406 cmd->server->id_entry->router->connection,
407 buffer->data, buffer->len,
412 /* If we are router then we will check our global list as well. */
413 if (cmd->server->server_type == SILC_ROUTER) {
415 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
416 nick, cmd->server->md5hash);
418 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
419 SILC_STATUS_ERR_NO_SUCH_NICK,
426 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
427 SILC_STATUS_ERR_NO_SUCH_NICK,
433 /* Send IDENTIFY reply */
434 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
435 tmp = silc_command_get_first_arg(cmd->payload, NULL);
436 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
437 packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
438 sp_buf->data, sp_buf->len,
439 id_string, SILC_ID_CLIENT_LEN,
441 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
442 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
443 silc_server_packet_send_dest(cmd->server, cmd->sock,
444 SILC_PACKET_COMMAND_REPLY, 0,
445 id, cmd->packet->src_id_type,
446 packet->data, packet->len, FALSE);
449 silc_server_packet_send(cmd->server, cmd->sock,
450 SILC_PACKET_COMMAND_REPLY, 0,
451 packet->data, packet->len, FALSE);
453 silc_free(id_string);
454 silc_buffer_free(packet);
462 silc_server_command_free(cmd);
465 /* Checks string for bad characters and returns TRUE if they are found. */
467 static int silc_server_command_bad_chars(char *nick)
469 if (strchr(nick, '\\')) return TRUE;
470 if (strchr(nick, '\"')) return TRUE;
471 if (strchr(nick, '´')) return TRUE;
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;
481 /* Server side of command NICK. Sets nickname for user. Setting
482 nickname causes generation of a new client ID for the client. The
483 new client ID is sent to the client after changing the nickname. */
485 SILC_SERVER_CMD_FUNC(nick)
487 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
488 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
489 SilcServer server = cmd->server;
490 SilcBuffer packet, sp_buf;
491 SilcClientID *new_id;
495 SILC_LOG_DEBUG(("Start"));
497 #define LCC(x) server->local_list->client_cache[(x) - 32]
498 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
500 /* Check number of arguments */
501 if (silc_command_get_arg_num(cmd->payload) < 1) {
502 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
503 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
508 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
509 if (silc_server_command_bad_chars(nick) == TRUE) {
510 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
511 SILC_STATUS_ERR_BAD_NICKNAME);
515 /* Create new Client ID */
516 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
517 cmd->server->md5hash, nick,
520 /* Send notify about nickname change to our router. We send the new
521 ID and ask to replace it with the old one. */
522 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
523 silc_server_send_replace_id(server, server->id_entry->router->connection,
525 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
526 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
528 /* If we are router we have to distribute the new Client ID to all
530 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
531 silc_server_send_replace_id(server, server->id_entry->router->connection,
533 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
534 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
536 /* Remove old cache entry */
537 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
538 LCCC(id_entry->nickname[0]),
539 SILC_ID_CLIENT, id_entry->id);
543 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
544 silc_free(id_entry->id);
547 /* Save the nickname as this client is our local client */
548 if (id_entry->nickname)
549 silc_free(id_entry->nickname);
551 id_entry->nickname = strdup(nick);
552 id_entry->id = new_id;
554 /* Update client cache */
555 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
556 id_entry->nickname, SILC_ID_CLIENT,
557 id_entry->id, (void *)id_entry);
559 /* Send the new Client ID as reply command back to client */
560 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
561 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
562 packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
563 sp_buf->data, sp_buf->len,
564 id_string, SILC_ID_CLIENT_LEN);
565 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
566 0, packet->data, packet->len, FALSE);
568 silc_free(id_string);
569 silc_buffer_free(packet);
573 silc_server_command_free(cmd);
578 SILC_SERVER_CMD_FUNC(list)
582 SILC_SERVER_CMD_FUNC(topic)
586 SILC_SERVER_CMD_FUNC(invite)
590 /* Quits connection to client. This gets called if client won't
591 close the connection even when it has issued QUIT command. */
593 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
595 SilcServer server = (SilcServer)context;
596 SilcSocketConnection sock = server->sockets[fd];
598 /* Free all client specific data, such as client entry and entires
599 on channels this client may be on. */
600 silc_server_free_sock_user_data(server, sock);
602 /* Close the connection on our side */
603 silc_server_close_connection(server, sock);
606 /* Quits SILC session. This is the normal way to disconnect client. */
608 SILC_SERVER_CMD_FUNC(quit)
610 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
611 SilcServer server = cmd->server;
612 SilcSocketConnection sock = cmd->sock;
614 SILC_LOG_DEBUG(("Start"));
616 /* We quit the connection with little timeout */
617 silc_task_register(server->timeout_queue, sock->sock,
618 silc_server_command_quit_cb, server,
619 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
621 silc_server_command_free(cmd);
624 SILC_SERVER_CMD_FUNC(kill)
628 SILC_SERVER_CMD_FUNC(info)
632 SILC_SERVER_CMD_FUNC(connect)
636 SILC_SERVER_CMD_FUNC(ping)
640 SILC_SERVER_CMD_FUNC(oper)
649 SilcChannelList *channel;
651 } JoinInternalContext;
653 SILC_TASK_CALLBACK(silc_server_command_join_notify)
655 JoinInternalContext *ctx = (JoinInternalContext *)context;
657 if (ctx->channel->key && ctx->channel->key_len) {
658 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
659 "%s (%s@%s) has joined channel %s",
660 ctx->nickname, ctx->username,
661 ctx->hostname, ctx->channel_name);
664 silc_task_register(ctx->server->timeout_queue, fd,
665 silc_server_command_join_notify, context,
666 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
670 /* Server side of command JOIN. Joins client into requested channel. If
671 the channel does not exist it will be created. */
673 SILC_SERVER_CMD_FUNC(join)
675 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
676 SilcServer server = cmd->server;
677 SilcSocketConnection sock = cmd->sock;
678 SilcBuffer buffer = cmd->packet->buffer;
679 int argc, i, tmp_len;
680 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
681 unsigned char *passphrase;
682 SilcChannelList *channel;
683 SilcServerID *router_id;
684 SilcIDCache *id_cache;
685 SilcBuffer packet, sp_buf;
686 SilcClientList *client;
688 SILC_LOG_DEBUG(("Start"));
690 #define LCC(x) server->local_list->channel_cache[(x) - 32]
691 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
693 /* Check number of parameters */
694 argc = silc_command_get_arg_num(cmd->payload);
696 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
697 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
701 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
702 SILC_STATUS_ERR_TOO_MANY_PARAMS);
706 /* Get channel name */
707 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
708 if (silc_server_command_bad_chars(tmp) == TRUE) {
709 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
710 SILC_STATUS_ERR_BAD_CHANNEL);
713 channel_name = strdup(tmp);
716 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
718 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
719 memcpy(passphrase, tmp, tmp_len);
722 /* Get cipher name */
723 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
725 /* See if the channel exists */
726 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
727 channel_name, &id_cache) == FALSE) {
728 /* Channel not found */
731 /* If we are standalone server we don't have a router, we just create
732 the channel by ourselves. */
733 if (server->standalone) {
734 router_id = server->id;
735 channel = silc_server_new_channel(server, router_id,
736 cipher, channel_name);
740 /* No channel ID found, the channel does not exist on our server.
741 We send JOIN command to our router which will handle the joining
742 procedure (either creates the channel if it doesn't exist or
743 joins the client to it) - if we are normal server. */
744 if (server->server_type == SILC_SERVER) {
746 /* Forward the received JOIN command to the router */
747 silc_buffer_push(buffer, buffer->data - buffer->head);
748 silc_server_packet_forward(server, (SilcSocketConnection)
749 server->id_entry->router->connection,
750 buffer->data, buffer->len,
753 /* Add the command to be pending. It will be re-executed after
754 router has replied back to us. */
756 silc_server_command_pending(SILC_COMMAND_JOIN,
757 silc_server_command_join, context);
762 /* If we are router and the channel does not exist we will check our
763 global list for the channel. */
764 if (!id_cache && server->server_type == SILC_ROUTER) {
766 /* Notify all routers about the new channel in SILC network. */
767 if (!server->standalone) {
769 silc_server_send_new_id(server, server->id_entry->router->connection,
771 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
777 channel = (SilcChannelList *)id_cache->context;
781 /* XXX must check whether the client already is on the channel */
783 /* Join the client to the channel */
784 i = channel->user_list_count;
785 channel->user_list = silc_realloc(channel->user_list,
786 sizeof(*channel->user_list) * (i + 1));
787 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
789 /* If the JOIN request was forwarded to us we will make a bit slower
790 query to get the client pointer. Otherwise, we get the client pointer
792 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
793 client = (SilcClientList *)sock->user_data;
794 channel->user_list[i].client = client;
796 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
797 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
798 channel->user_list[i].client = client;
801 channel->user_list_count++;
803 i = client->channel_count;
804 client->channel = silc_realloc(client->channel,
805 sizeof(*client->channel) * (i + 1));
806 client->channel[i] = channel;
807 client->channel_count++;
809 /* Notify router about new user on channel. If we are normal server
810 we send it to our router, if we are router we send it to our
812 if (!server->standalone) {
816 /* Send Channel ID to the client */
818 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
819 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
822 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 3,
823 sp_buf->data, sp_buf->len,
824 channel_name, strlen(channel_name),
825 id_string, SILC_ID_CHANNEL_LEN);
828 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
829 sp_buf->data, sp_buf->len,
830 channel_name, strlen(channel_name),
831 id_string, SILC_ID_CHANNEL_LEN,
833 strlen(channel->topic));
835 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
836 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
837 silc_server_packet_send_dest(cmd->server, cmd->sock,
838 SILC_PACKET_COMMAND_REPLY, 0,
839 id, cmd->packet->src_id_type,
840 packet->data, packet->len, FALSE);
843 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
844 packet->data, packet->len, FALSE);
846 silc_buffer_free(packet);
850 /* Send channel key to the client. Client cannot start transmitting
851 to the channel until we have sent the key. */
853 tmp_len = strlen(channel->channel_key->cipher->name);
855 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
857 channel->channel_key->cipher->name,
858 channel->key_len, channel->key);
860 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
861 packet->data, packet->len, FALSE);
862 silc_buffer_free(packet);
866 silc_free(id_string);
868 /* Finally, send notify message to all clients on the channel about
869 new user on the channel. */
870 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
872 silc_server_send_notify_to_channel(server, channel,
873 "%s (%s@%s) has joined channel %s",
874 client->nickname, client->username,
875 sock->hostname ? sock->hostname :
876 sock->ip, channel_name);
878 /* This is pending command request. Send the notify after we have
879 received the key for the channel from the router. */
880 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
881 ctx->channel_name = channel_name;
882 ctx->nickname = client->nickname;
883 ctx->username = client->username;
884 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
885 ctx->channel = channel;
886 ctx->server = server;
887 silc_task_register(server->timeout_queue, sock->sock,
888 silc_server_command_join_notify, ctx,
889 0, 100000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
894 silc_server_command_free(cmd);
899 /* Server side of command MOTD. Sends servers current "message of the
900 day" to the client. */
902 SILC_SERVER_CMD_FUNC(motd)
905 SILC_LOG_DEBUG(("Start"));
909 SILC_SERVER_CMD_FUNC(umode)
913 SILC_SERVER_CMD_FUNC(cmode)
917 SILC_SERVER_CMD_FUNC(kick)
921 SILC_SERVER_CMD_FUNC(restart)
925 SILC_SERVER_CMD_FUNC(close)
929 SILC_SERVER_CMD_FUNC(die)
933 SILC_SERVER_CMD_FUNC(silcoper)
937 SILC_SERVER_CMD_FUNC(leave)
941 SILC_SERVER_CMD_FUNC(names)