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.3 2000/07/03 05:52:22 priikone
24 * Implemented LEAVE command.
26 * Revision 1.2 2000/06/28 05:06:38 priikone
27 * Shorter timeout for channel joining notify.
29 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
30 * Importet from internal CVS/Added Log headers.
35 #include "serverincludes.h"
36 #include "server_internal.h"
38 /* Server command list. */
39 SilcServerCommand silc_command_list[] =
41 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
42 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
43 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
44 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
45 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
46 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
47 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
48 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
49 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
50 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(connect, CONNECT,
52 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
53 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
55 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
56 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
57 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
58 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
59 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
60 SILC_SERVER_CMD(restart, RESTART,
61 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
62 SILC_SERVER_CMD(close, CLOSE,
63 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
64 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
65 SILC_SERVER_CMD(silcoper, SILCOPER,
66 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
67 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
68 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
73 /* List of pending commands. */
74 SilcServerCommandPending *silc_command_pending = NULL;
76 /* Add new pending command to the list of pending commands. Currently
77 pending commands are executed from command replies, thus we can
78 execute any command after receiving some specific command reply.
80 The argument `reply_cmd' is the command reply from where the callback
81 function is to be called, thus, it IS NOT the command to be executed. */
83 void silc_server_command_pending(SilcCommand reply_cmd,
84 SilcCommandCb callback,
87 SilcServerCommandPending *reply, *r;
89 reply = silc_calloc(1, sizeof(*reply));
90 reply->reply_cmd = reply_cmd;
91 reply->context = context;
92 reply->callback = callback;
94 if (silc_command_pending == NULL) {
95 silc_command_pending = reply;
99 for (r = silc_command_pending; r; r = r->next) {
100 if (r->next == NULL) {
107 /* Deletes pending command by reply command type. */
109 void silc_server_command_pending_del(SilcCommand reply_cmd)
111 SilcServerCommandPending *r, *tmp;
113 if (silc_command_pending) {
114 if (silc_command_pending->reply_cmd == reply_cmd) {
115 silc_free(silc_command_pending);
116 silc_command_pending = NULL;
120 for (r = silc_command_pending; r; r = r->next) {
121 if (r->next && r->next->reply_cmd == reply_cmd) {
123 r->next = r->next->next;
131 /* Free's the command context allocated before executing the command */
133 static void silc_server_command_free(SilcServerCommandContext cmd)
136 silc_command_free_payload(cmd->payload);
141 /* Sends command status message as command reply packet. */
144 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
146 SilcCommandStatus status,
148 unsigned int msg_len)
150 SilcBuffer sp_buf, buffer;
152 SILC_LOG_DEBUG(("Sending command status %d", status));
154 sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
155 buffer = silc_command_encode_payload_va(command, 1,
156 sp_buf->data, sp_buf->len);
157 silc_server_packet_send(cmd->server, cmd->sock,
158 SILC_PACKET_COMMAND_REPLY, 0,
159 buffer->data, buffer->len, FALSE);
160 silc_buffer_free(buffer);
161 silc_buffer_free(sp_buf);
164 /* Sends simple status message as command reply packet */
167 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
169 SilcCommandStatus status)
171 SilcBuffer sp_buf, buffer;
173 SILC_LOG_DEBUG(("Sending command status %d", status));
175 sp_buf = silc_command_encode_status_payload(status, NULL, 0);
176 buffer = silc_command_encode_payload_va(command, 1,
177 sp_buf->data, sp_buf->len);
178 silc_server_packet_send(cmd->server, cmd->sock,
179 SILC_PACKET_COMMAND_REPLY, 0,
180 buffer->data, buffer->len, FALSE);
181 silc_buffer_free(buffer);
182 silc_buffer_free(sp_buf);
185 /* Server side of command WHOIS. Processes user's query and sends found
186 results as command replies back to the client. */
188 SILC_SERVER_CMD_FUNC(whois)
190 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
191 char *tmp, *nick = NULL, *server = NULL;
192 unsigned int argc, count = 0, len;
193 SilcClientList *entry;
194 SilcBuffer sp_buf, packet;
195 unsigned char *id_string;
197 SILC_LOG_DEBUG(("Start"));
199 argc = silc_command_get_arg_num(cmd->payload);
201 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
202 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
206 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
207 SILC_STATUS_ERR_TOO_MANY_PARAMS);
211 /* Get the nickname@server string and parse it. */
212 tmp = silc_command_get_first_arg(cmd->payload, NULL);
214 if (strchr(tmp, '@')) {
215 len = strcspn(tmp, "@");
216 nick = silc_calloc(len + 1, sizeof(char));
217 memcpy(nick, tmp, len);
218 server = silc_calloc(strlen(tmp) - len, sizeof(char));
219 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
224 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
225 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
229 /* Get the max count of reply messages allowed */
231 tmp = silc_command_get_next_arg(cmd->payload, NULL);
233 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
234 SILC_STATUS_ERR_TOO_MANY_PARAMS);
244 /* Then, make the query from our local client list */
245 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
249 /* If we are normal server and are connected to a router we will
250 make global query from the router. */
251 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
256 /* If we are router then we will check our global list as well. */
257 if (cmd->server->server_type == SILC_ROUTER) {
259 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
262 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
263 SILC_STATUS_ERR_NO_SUCH_NICK,
270 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
271 SILC_STATUS_ERR_NO_SUCH_NICK,
277 /* XXX, works only for local server info */
279 /* Send WHOIS reply */
280 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
281 tmp = silc_command_get_first_arg(cmd->payload, NULL),
282 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
285 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
286 char nh[256], uh[256];
287 SilcSocketConnection hsock;
289 memset(uh, 0, sizeof(uh));
290 memset(nh, 0, sizeof(nh));
292 strncat(nh, entry->nickname, strlen(entry->nickname));
294 len = entry->router ? strlen(entry->router->server_name) :
295 strlen(cmd->server->server_name);
296 strncat(nh, entry->router ? entry->router->server_name :
297 cmd->server->server_name, len);
299 strncat(uh, entry->username, strlen(entry->username));
301 hsock = (SilcSocketConnection)entry->connection;
302 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
303 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
308 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5,
309 sp_buf->data, sp_buf->len,
310 id_string, SILC_ID_CLIENT_LEN,
314 strlen(entry->userinfo));
317 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
318 sp_buf->data, sp_buf->len,
319 id_string, SILC_ID_CLIENT_LEN,
326 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
327 sp_buf->data, sp_buf->len,
328 id_string, SILC_ID_CLIENT_LEN,
329 entry->nickname, strlen(entry->nickname),
330 tmp, strlen(tmp)); /* XXX */
332 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
333 0, packet->data, packet->len, FALSE);
335 silc_free(id_string);
336 silc_buffer_free(packet);
340 silc_server_command_free(cmd);
343 SILC_SERVER_CMD_FUNC(whowas)
347 SILC_SERVER_CMD_FUNC(identify)
349 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
350 char *tmp, *nick = NULL, *server = NULL;
351 unsigned int argc, count = 0, len;
352 SilcClientList *entry;
353 SilcBuffer sp_buf, packet;
354 unsigned char *id_string;
356 SILC_LOG_DEBUG(("Start"));
358 argc = silc_command_get_arg_num(cmd->payload);
360 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
361 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
365 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
366 SILC_STATUS_ERR_TOO_MANY_PARAMS);
370 /* Get the nickname@server string and parse it. */
371 tmp = silc_command_get_first_arg(cmd->payload, NULL);
373 if (strchr(tmp, '@')) {
374 len = strcspn(tmp, "@");
375 nick = silc_calloc(len + 1, sizeof(char));
376 memcpy(nick, tmp, len);
377 server = silc_calloc(strlen(tmp) - len, sizeof(char));
378 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
383 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
384 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
388 /* Get the max count of reply messages allowed */
390 tmp = silc_command_get_next_arg(cmd->payload, NULL);
392 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
393 SILC_STATUS_ERR_TOO_MANY_PARAMS);
399 /* Then, make the query from our local client list */
400 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
401 nick, cmd->server->md5hash);
404 /* If we are normal server and are connected to a router we will
405 make global query from the router. */
406 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
407 SilcBuffer buffer = cmd->packet->buffer;
409 /* Send IDENTIFY command to our router */
410 silc_buffer_push(buffer, buffer->data - buffer->head);
411 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
412 cmd->server->id_entry->router->connection,
413 buffer->data, buffer->len, TRUE);
417 /* If we are router then we will check our global list as well. */
418 if (cmd->server->server_type == SILC_ROUTER) {
420 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
421 nick, cmd->server->md5hash);
423 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
424 SILC_STATUS_ERR_NO_SUCH_NICK,
431 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
432 SILC_STATUS_ERR_NO_SUCH_NICK,
438 /* Send IDENTIFY reply */
439 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
440 tmp = silc_command_get_first_arg(cmd->payload, NULL);
441 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
442 packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
443 sp_buf->data, sp_buf->len,
444 id_string, SILC_ID_CLIENT_LEN,
447 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
448 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
449 silc_server_packet_send_dest(cmd->server, cmd->sock,
450 SILC_PACKET_COMMAND_REPLY, 0,
451 id, cmd->packet->src_id_type,
452 packet->data, packet->len, FALSE);
456 silc_server_packet_send(cmd->server, cmd->sock,
457 SILC_PACKET_COMMAND_REPLY, 0,
458 packet->data, packet->len, FALSE);
460 silc_free(id_string);
461 silc_buffer_free(packet);
469 silc_server_command_free(cmd);
472 /* Checks string for bad characters and returns TRUE if they are found. */
474 static int silc_server_command_bad_chars(char *nick)
476 if (strchr(nick, '\\')) return TRUE;
477 if (strchr(nick, '\"')) return TRUE;
478 if (strchr(nick, '´')) return TRUE;
479 if (strchr(nick, '`')) return TRUE;
480 if (strchr(nick, '\'')) return TRUE;
481 if (strchr(nick, '*')) return TRUE;
482 if (strchr(nick, '/')) return TRUE;
483 if (strchr(nick, '@')) return TRUE;
488 /* Server side of command NICK. Sets nickname for user. Setting
489 nickname causes generation of a new client ID for the client. The
490 new client ID is sent to the client after changing the nickname. */
492 SILC_SERVER_CMD_FUNC(nick)
494 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
495 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
496 SilcServer server = cmd->server;
497 SilcBuffer packet, sp_buf;
498 SilcClientID *new_id;
502 SILC_LOG_DEBUG(("Start"));
504 #define LCC(x) server->local_list->client_cache[(x) - 32]
505 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
507 /* Check number of arguments */
508 if (silc_command_get_arg_num(cmd->payload) < 1) {
509 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
510 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
515 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
516 if (silc_server_command_bad_chars(nick) == TRUE) {
517 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
518 SILC_STATUS_ERR_BAD_NICKNAME);
522 /* Create new Client ID */
523 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
524 cmd->server->md5hash, nick,
527 /* Send notify about nickname change to our router. We send the new
528 ID and ask to replace it with the old one. */
529 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
530 silc_server_send_replace_id(server, server->id_entry->router->connection,
532 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
533 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
535 /* If we are router we have to distribute the new Client ID to all
537 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
538 silc_server_send_replace_id(server, server->id_entry->router->connection,
540 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
541 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
543 /* Remove old cache entry */
544 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
545 LCCC(id_entry->nickname[0]),
546 SILC_ID_CLIENT, id_entry->id);
550 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
551 silc_free(id_entry->id);
554 /* Save the nickname as this client is our local client */
555 if (id_entry->nickname)
556 silc_free(id_entry->nickname);
558 id_entry->nickname = strdup(nick);
559 id_entry->id = new_id;
561 /* Update client cache */
562 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
563 id_entry->nickname, SILC_ID_CLIENT,
564 id_entry->id, (void *)id_entry);
566 /* Send the new Client ID as reply command back to client */
567 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
568 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
569 packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
570 sp_buf->data, sp_buf->len,
571 id_string, SILC_ID_CLIENT_LEN);
572 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
573 0, packet->data, packet->len, FALSE);
575 silc_free(id_string);
576 silc_buffer_free(packet);
580 silc_server_command_free(cmd);
585 SILC_SERVER_CMD_FUNC(list)
589 SILC_SERVER_CMD_FUNC(topic)
593 SILC_SERVER_CMD_FUNC(invite)
597 /* Quits connection to client. This gets called if client won't
598 close the connection even when it has issued QUIT command. */
600 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
602 SilcServer server = (SilcServer)context;
603 SilcSocketConnection sock = server->sockets[fd];
605 /* Free all client specific data, such as client entry and entires
606 on channels this client may be on. */
607 silc_server_free_sock_user_data(server, sock);
609 /* Close the connection on our side */
610 silc_server_close_connection(server, sock);
613 /* Quits SILC session. This is the normal way to disconnect client. */
615 SILC_SERVER_CMD_FUNC(quit)
617 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
618 SilcServer server = cmd->server;
619 SilcSocketConnection sock = cmd->sock;
621 SILC_LOG_DEBUG(("Start"));
623 /* We quit the connection with little timeout */
624 silc_task_register(server->timeout_queue, sock->sock,
625 silc_server_command_quit_cb, server,
626 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
628 silc_server_command_free(cmd);
631 SILC_SERVER_CMD_FUNC(kill)
635 SILC_SERVER_CMD_FUNC(info)
639 SILC_SERVER_CMD_FUNC(connect)
643 SILC_SERVER_CMD_FUNC(ping)
647 SILC_SERVER_CMD_FUNC(oper)
656 SilcChannelList *channel;
658 } JoinInternalContext;
660 SILC_TASK_CALLBACK(silc_server_command_join_notify)
662 JoinInternalContext *ctx = (JoinInternalContext *)context;
664 if (ctx->channel->key && ctx->channel->key_len) {
665 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
666 "%s (%s@%s) has joined channel %s",
667 ctx->nickname, ctx->username,
668 ctx->hostname, ctx->channel_name);
671 silc_task_register(ctx->server->timeout_queue, fd,
672 silc_server_command_join_notify, context,
673 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
677 /* Server side of command JOIN. Joins client into requested channel. If
678 the channel does not exist it will be created. */
680 SILC_SERVER_CMD_FUNC(join)
682 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
683 SilcServer server = cmd->server;
684 SilcSocketConnection sock = cmd->sock;
685 SilcBuffer buffer = cmd->packet->buffer;
686 int argc, i, tmp_len;
687 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
688 unsigned char *passphrase, mode[4];
689 SilcChannelList *channel;
690 SilcServerID *router_id;
691 SilcIDCache *id_cache;
692 SilcBuffer packet, sp_buf;
693 SilcClientList *client;
695 SILC_LOG_DEBUG(("Start"));
697 #define LCC(x) server->local_list->channel_cache[(x) - 32]
698 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
700 /* Check number of parameters */
701 argc = silc_command_get_arg_num(cmd->payload);
703 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
704 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
708 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
709 SILC_STATUS_ERR_TOO_MANY_PARAMS);
713 /* Get channel name */
714 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
715 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
716 memcpy(channel_name, tmp, tmp_len);
717 if (silc_server_command_bad_chars(tmp) == TRUE) {
718 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
719 SILC_STATUS_ERR_BAD_CHANNEL);
720 silc_free(channel_name);
725 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
727 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
728 memcpy(passphrase, tmp, tmp_len);
731 /* Get cipher name */
732 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
734 /* See if the channel exists */
735 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
736 channel_name, &id_cache) == FALSE) {
737 /* Channel not found */
740 /* If we are standalone server we don't have a router, we just create
741 the channel by ourselves. */
742 if (server->standalone) {
743 router_id = server->id;
744 channel = silc_server_new_channel(server, router_id,
745 cipher, channel_name);
749 /* No channel ID found, the channel does not exist on our server.
750 We send JOIN command to our router which will handle the joining
751 procedure (either creates the channel if it doesn't exist or
752 joins the client to it) - if we are normal server. */
753 if (server->server_type == SILC_SERVER) {
755 /* Forward the original JOIN command to the router */
756 silc_buffer_push(buffer, buffer->data - buffer->head);
757 silc_server_packet_forward(server, (SilcSocketConnection)
758 server->id_entry->router->connection,
759 buffer->data, buffer->len, TRUE);
761 /* Add the command to be pending. It will be re-executed after
762 router has replied back to us. */
764 silc_server_command_pending(SILC_COMMAND_JOIN,
765 silc_server_command_join, context);
770 /* If we are router and the channel does not exist we will check our
771 global list for the channel. */
772 if (!id_cache && server->server_type == SILC_ROUTER) {
774 /* Notify all routers about the new channel in SILC network. */
775 if (!server->standalone) {
777 silc_server_send_new_id(server, server->id_entry->router->connection,
779 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
785 channel = (SilcChannelList *)id_cache->context;
789 /* XXX must check whether the client already is on the channel */
791 /* Join the client to the channel */
792 i = channel->user_list_count;
793 channel->user_list = silc_realloc(channel->user_list,
794 sizeof(*channel->user_list) * (i + 1));
795 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
797 /* If the JOIN request was forwarded to us we will make a bit slower
798 query to get the client pointer. Otherwise, we get the client pointer
800 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
801 client = (SilcClientList *)sock->user_data;
802 channel->user_list[i].client = client;
804 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
805 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
806 channel->user_list[i].client = client;
809 channel->user_list_count++;
811 i = client->channel_count;
812 client->channel = silc_realloc(client->channel,
813 sizeof(*client->channel) * (i + 1));
814 client->channel[i] = channel;
815 client->channel_count++;
817 /* Notify router about new user on channel. If we are normal server
818 we send it to our router, if we are router we send it to our
820 if (!server->standalone) {
824 /* Send command reply to the client. Client receives the Channe ID,
825 channel mode and possibly other information in this reply packet. */
827 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
828 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
829 SILC_PUT32_MSB(channel->mode, mode);
833 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
834 sp_buf->data, sp_buf->len,
835 channel_name, strlen(channel_name),
836 id_string, SILC_ID_CHANNEL_LEN,
840 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 5,
841 sp_buf->data, sp_buf->len,
842 channel_name, strlen(channel_name),
843 id_string, SILC_ID_CHANNEL_LEN,
845 channel->topic, strlen(channel->topic));
847 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
848 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
849 silc_server_packet_send_dest(cmd->server, cmd->sock,
850 SILC_PACKET_COMMAND_REPLY, 0,
851 id, cmd->packet->src_id_type,
852 packet->data, packet->len, FALSE);
855 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
856 packet->data, packet->len, FALSE);
858 silc_buffer_free(packet);
862 /* Send channel key to the client. Client cannot start transmitting
863 to the channel until we have sent the key. */
865 tmp_len = strlen(channel->channel_key->cipher->name);
867 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
869 channel->channel_key->cipher->name,
870 channel->key_len / 8, channel->key);
872 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
873 packet->data, packet->len, FALSE);
874 silc_buffer_free(packet);
878 silc_free(id_string);
880 /* Finally, send notify message to all clients on the channel about
881 new user on the channel. */
882 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
884 silc_server_send_notify_to_channel(server, channel,
885 "%s (%s@%s) has joined channel %s",
886 client->nickname, client->username,
887 sock->hostname ? sock->hostname :
888 sock->ip, channel_name);
890 /* This is pending command request. Send the notify after we have
891 received the key for the channel from the router. */
892 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
893 ctx->channel_name = channel_name;
894 ctx->nickname = client->nickname;
895 ctx->username = client->username;
896 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
897 ctx->channel = channel;
898 ctx->server = server;
899 silc_task_register(server->timeout_queue, sock->sock,
900 silc_server_command_join_notify, ctx,
901 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
906 silc_server_command_free(cmd);
911 /* Server side of command MOTD. Sends servers current "message of the
912 day" to the client. */
914 SILC_SERVER_CMD_FUNC(motd)
917 SILC_LOG_DEBUG(("Start"));
921 SILC_SERVER_CMD_FUNC(umode)
925 SILC_SERVER_CMD_FUNC(cmode)
929 SILC_SERVER_CMD_FUNC(kick)
933 SILC_SERVER_CMD_FUNC(restart)
937 SILC_SERVER_CMD_FUNC(close)
941 SILC_SERVER_CMD_FUNC(die)
945 SILC_SERVER_CMD_FUNC(silcoper)
949 /* Server side command of LEAVE. Removes client from a channel. */
951 SILC_SERVER_CMD_FUNC(leave)
953 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
954 SilcSocketConnection sock = cmd->sock;
955 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
956 SilcServer server = cmd->server;
958 SilcChannelList *channel;
960 unsigned int i, argc, key_len;
961 unsigned char *tmp, channel_key[32];
963 SILC_LOG_DEBUG(("Start"));
965 argc = silc_command_get_arg_num(cmd->payload);
967 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
968 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
972 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
973 SILC_STATUS_ERR_TOO_MANY_PARAMS);
977 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
979 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
980 SILC_STATUS_ERR_BAD_CHANNEL_ID);
985 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
987 /* Get channel entry */
988 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
990 /* Remove client from channel */
991 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
992 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
995 /* If the channel does not exist anymore we won't send anything */
999 /* Re-generate channel key */
1000 key_len = channel->key_len / 8;
1001 for (i = 0; i < key_len; i++)
1002 channel_key[i] = silc_rng_get_byte(server->rng);
1003 channel->channel_key->cipher->set_key(channel->channel_key->context,
1004 channel_key, key_len);
1005 memset(channel->key, 0, key_len);
1006 silc_free(channel->key);
1007 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1008 memcpy(channel->key, channel_key, key_len);
1009 memset(channel_key, 0, sizeof(channel_key));
1011 /* Encode channel key payload to be distributed on the channel */
1013 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1014 strlen(channel->channel_key->cipher->name),
1015 channel->channel_key->cipher->name,
1016 key_len, channel->key);
1018 /* If we are normal server then we will send it to our router. If we
1019 are router we will send it to all local servers that has clients on
1021 if (server->server_type == SILC_SERVER) {
1022 if (!server->standalone)
1023 silc_server_packet_send(server,
1024 cmd->server->id_entry->router->connection,
1025 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1031 /* Send to locally connected clients on the channel */
1032 silc_server_packet_send_local_channel(server, channel,
1033 SILC_PACKET_CHANNEL_KEY, 0,
1034 packet->data, packet->len, FALSE);
1036 silc_buffer_free(packet);
1040 silc_server_command_free(cmd);
1043 SILC_SERVER_CMD_FUNC(names)