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.6 2000/07/06 10:20:59 priikone
24 * Cipher name in joining is not mandatory, removed check.
26 * Revision 1.5 2000/07/06 07:16:43 priikone
27 * Fixed a wrong way of sending command replies. The fixed way
28 * does comply with the protocol.
30 * Revision 1.4 2000/07/05 06:13:38 priikone
31 * Added PING, INVITE and NAMES command.
33 * Revision 1.3 2000/07/03 05:52:22 priikone
34 * Implemented LEAVE command.
36 * Revision 1.2 2000/06/28 05:06:38 priikone
37 * Shorter timeout for channel joining notify.
39 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
40 * Imported from internal CVS/Added Log headers.
45 #include "serverincludes.h"
46 #include "server_internal.h"
48 /* Server command list. */
49 SilcServerCommand silc_command_list[] =
51 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
52 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
53 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
55 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
56 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
57 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
58 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
59 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
60 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
61 SILC_SERVER_CMD(connect, CONNECT,
62 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
63 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
64 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
65 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
66 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
67 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
68 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
69 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
70 SILC_SERVER_CMD(restart, RESTART,
71 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
72 SILC_SERVER_CMD(close, CLOSE,
73 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
74 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
75 SILC_SERVER_CMD(silcoper, SILCOPER,
76 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
77 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
78 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
83 /* List of pending commands. */
84 SilcServerCommandPending *silc_command_pending = NULL;
86 /* Add new pending command to the list of pending commands. Currently
87 pending commands are executed from command replies, thus we can
88 execute any command after receiving some specific command reply.
90 The argument `reply_cmd' is the command reply from where the callback
91 function is to be called, thus, it IS NOT the command to be executed. */
93 void silc_server_command_pending(SilcCommand reply_cmd,
94 SilcCommandCb callback,
97 SilcServerCommandPending *reply, *r;
99 reply = silc_calloc(1, sizeof(*reply));
100 reply->reply_cmd = reply_cmd;
101 reply->context = context;
102 reply->callback = callback;
104 if (silc_command_pending == NULL) {
105 silc_command_pending = reply;
109 for (r = silc_command_pending; r; r = r->next) {
110 if (r->next == NULL) {
117 /* Deletes pending command by reply command type. */
119 void silc_server_command_pending_del(SilcCommand reply_cmd)
121 SilcServerCommandPending *r, *tmp;
123 if (silc_command_pending) {
124 if (silc_command_pending->reply_cmd == reply_cmd) {
125 silc_free(silc_command_pending);
126 silc_command_pending = NULL;
130 for (r = silc_command_pending; r; r = r->next) {
131 if (r->next && r->next->reply_cmd == reply_cmd) {
133 r->next = r->next->next;
141 /* Free's the command context allocated before executing the command */
143 static void silc_server_command_free(SilcServerCommandContext cmd)
146 silc_command_free_payload(cmd->payload);
151 #define SILC_COMMAND_STATUS_DATA(x) \
154 /* Sends simple status message as command reply packet */
157 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
159 SilcCommandStatus status)
163 SILC_LOG_DEBUG(("Sending command status %d", status));
165 buffer = silc_command_encode_reply_payload_va(command, status, 0);
166 silc_server_packet_send(cmd->server, cmd->sock,
167 SILC_PACKET_COMMAND_REPLY, 0,
168 buffer->data, buffer->len, FALSE);
169 silc_buffer_free(buffer);
172 /* Sends command status reply with one extra argument. The argument
173 type must be sent as argument. */
176 silc_server_command_send_status_data(SilcServerCommandContext cmd,
178 SilcCommandStatus status,
179 unsigned int arg_type,
181 unsigned int arg_len)
185 SILC_LOG_DEBUG(("Sending command status %d", status));
187 buffer = silc_command_encode_reply_payload_va(command, status, 1,
188 arg_type, arg, arg_len);
189 silc_server_packet_send(cmd->server, cmd->sock,
190 SILC_PACKET_COMMAND_REPLY, 0,
191 buffer->data, buffer->len, FALSE);
192 silc_buffer_free(buffer);
195 /* Server side of command WHOIS. Processes user's query and sends found
196 results as command replies back to the client. */
198 SILC_SERVER_CMD_FUNC(whois)
200 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
201 char *tmp, *nick = NULL, *server = NULL;
202 unsigned int argc, count = 0, len;
203 SilcClientList *entry;
205 unsigned char *id_string;
207 SILC_LOG_DEBUG(("Start"));
209 argc = silc_command_get_arg_num(cmd->payload);
211 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
212 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
216 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
217 SILC_STATUS_ERR_TOO_MANY_PARAMS);
221 /* Get the nickname@server string and parse it. */
222 tmp = silc_command_get_first_arg(cmd->payload, NULL);
224 if (strchr(tmp, '@')) {
225 len = strcspn(tmp, "@");
226 nick = silc_calloc(len + 1, sizeof(char));
227 memcpy(nick, tmp, len);
228 server = silc_calloc(strlen(tmp) - len, sizeof(char));
229 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
234 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
235 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
239 /* Get the max count of reply messages allowed */
241 tmp = silc_command_get_next_arg(cmd->payload, NULL);
243 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
244 SILC_STATUS_ERR_TOO_MANY_PARAMS);
254 /* Then, make the query from our local client list */
255 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
259 /* If we are normal server and are connected to a router we will
260 make global query from the router. */
261 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
266 /* If we are router then we will check our global list as well. */
267 if (cmd->server->server_type == SILC_ROUTER) {
269 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
272 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
273 SILC_STATUS_ERR_NO_SUCH_NICK,
274 3, tmp, strlen(tmp));
280 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
281 SILC_STATUS_ERR_NO_SUCH_NICK,
282 3, tmp, strlen(tmp));
287 /* XXX, works only for local server info */
289 /* Send WHOIS reply */
290 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
291 tmp = silc_command_get_first_arg(cmd->payload, NULL);
294 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
295 char nh[256], uh[256];
296 SilcSocketConnection hsock;
298 memset(uh, 0, sizeof(uh));
299 memset(nh, 0, sizeof(nh));
301 strncat(nh, entry->nickname, strlen(entry->nickname));
303 len = entry->router ? strlen(entry->router->server_name) :
304 strlen(cmd->server->server_name);
305 strncat(nh, entry->router ? entry->router->server_name :
306 cmd->server->server_name, len);
308 strncat(uh, entry->username, strlen(entry->username));
310 hsock = (SilcSocketConnection)entry->connection;
311 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
312 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
317 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
319 2, id_string, SILC_ID_CLIENT_LEN,
323 strlen(entry->userinfo));
326 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
328 2, id_string, SILC_ID_CLIENT_LEN,
335 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
337 2, id_string, SILC_ID_CLIENT_LEN,
339 strlen(entry->nickname),
340 4, tmp, strlen(tmp)); /* XXX */
342 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
343 0, packet->data, packet->len, FALSE);
345 silc_free(id_string);
346 silc_buffer_free(packet);
349 silc_server_command_free(cmd);
352 SILC_SERVER_CMD_FUNC(whowas)
356 SILC_SERVER_CMD_FUNC(identify)
358 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
359 char *tmp, *nick = NULL, *server = NULL;
360 unsigned int argc, count = 0, len;
361 SilcClientList *entry; SilcBuffer packet;
362 unsigned char *id_string;
364 SILC_LOG_DEBUG(("Start"));
366 argc = silc_command_get_arg_num(cmd->payload);
368 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
369 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
373 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
374 SILC_STATUS_ERR_TOO_MANY_PARAMS);
378 /* Get the nickname@server string and parse it. */
379 tmp = silc_command_get_first_arg(cmd->payload, NULL);
381 if (strchr(tmp, '@')) {
382 len = strcspn(tmp, "@");
383 nick = silc_calloc(len + 1, sizeof(char));
384 memcpy(nick, tmp, len);
385 server = silc_calloc(strlen(tmp) - len, sizeof(char));
386 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
391 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
392 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
396 /* Get the max count of reply messages allowed */
398 tmp = silc_command_get_next_arg(cmd->payload, NULL);
400 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
401 SILC_STATUS_ERR_TOO_MANY_PARAMS);
407 /* Then, make the query from our local client list */
408 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
409 nick, cmd->server->md5hash);
412 /* If we are normal server and are connected to a router we will
413 make global query from the router. */
414 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
415 SilcBuffer buffer = cmd->packet->buffer;
417 /* Send IDENTIFY command to our router */
418 silc_buffer_push(buffer, buffer->data - buffer->head);
419 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
420 cmd->server->id_entry->router->connection,
421 buffer->data, buffer->len, TRUE);
425 /* If we are router then we will check our global list as well. */
426 if (cmd->server->server_type == SILC_ROUTER) {
428 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
429 nick, cmd->server->md5hash);
431 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
432 SILC_STATUS_ERR_NO_SUCH_NICK,
433 3, tmp, strlen(tmp));
439 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
440 SILC_STATUS_ERR_NO_SUCH_NICK,
441 3, tmp, strlen(tmp));
446 /* Send IDENTIFY reply */
447 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
448 tmp = silc_command_get_first_arg(cmd->payload, NULL);
449 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
453 3, nick, strlen(nick));
455 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
456 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
457 silc_server_packet_send_dest(cmd->server, cmd->sock,
458 SILC_PACKET_COMMAND_REPLY, 0,
459 id, cmd->packet->src_id_type,
460 packet->data, packet->len, FALSE);
464 silc_server_packet_send(cmd->server, cmd->sock,
465 SILC_PACKET_COMMAND_REPLY, 0,
466 packet->data, packet->len, FALSE);
468 silc_free(id_string);
469 silc_buffer_free(packet);
476 silc_server_command_free(cmd);
479 /* Checks string for bad characters and returns TRUE if they are found. */
481 static int silc_server_command_bad_chars(char *nick)
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;
488 if (strchr(nick, '*')) return TRUE;
489 if (strchr(nick, '/')) return TRUE;
490 if (strchr(nick, '@')) return TRUE;
495 /* Server side of command NICK. Sets nickname for user. Setting
496 nickname causes generation of a new client ID for the client. The
497 new client ID is sent to the client after changing the nickname. */
499 SILC_SERVER_CMD_FUNC(nick)
501 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
502 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
503 SilcServer server = cmd->server;
505 SilcClientID *new_id;
509 SILC_LOG_DEBUG(("Start"));
511 #define LCC(x) server->local_list->client_cache[(x) - 32]
512 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
514 /* Check number of arguments */
515 if (silc_command_get_arg_num(cmd->payload) < 1) {
516 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
517 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
522 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
523 if (silc_server_command_bad_chars(nick) == TRUE) {
524 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
525 SILC_STATUS_ERR_BAD_NICKNAME);
529 /* Create new Client ID */
530 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
531 cmd->server->md5hash, nick,
534 /* Send notify about nickname change to our router. We send the new
535 ID and ask to replace it with the old one. */
536 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
537 silc_server_send_replace_id(server, server->id_entry->router->connection,
539 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
540 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
542 /* If we are router we have to distribute the new Client ID to all
544 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
545 silc_server_send_replace_id(server, server->id_entry->router->connection,
547 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
548 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
550 /* Remove old cache entry */
551 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
552 LCCC(id_entry->nickname[0]),
553 SILC_ID_CLIENT, id_entry->id);
557 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
558 silc_free(id_entry->id);
561 /* Save the nickname as this client is our local client */
562 if (id_entry->nickname)
563 silc_free(id_entry->nickname);
565 id_entry->nickname = strdup(nick);
566 id_entry->id = new_id;
568 /* Update client cache */
569 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
570 id_entry->nickname, SILC_ID_CLIENT,
571 id_entry->id, (void *)id_entry);
573 /* Send the new Client ID as reply command back to client */
574 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
575 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
579 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
580 0, packet->data, packet->len, FALSE);
582 silc_free(id_string);
583 silc_buffer_free(packet);
586 silc_server_command_free(cmd);
591 SILC_SERVER_CMD_FUNC(list)
595 SILC_SERVER_CMD_FUNC(topic)
599 /* Server side of INVITE command. Invites some client to join some channel. */
601 SILC_SERVER_CMD_FUNC(invite)
603 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
604 SilcServer server = cmd->server;
605 SilcSocketConnection sock = cmd->sock, dest_sock;
606 SilcClientList *sender, *dest;
607 SilcClientID *dest_id;
608 SilcChannelList *channel;
609 SilcChannelID *channel_id;
610 unsigned int argc, len;
611 unsigned char *id_string;
613 /* Check number of arguments */
614 argc = silc_command_get_arg_num(cmd->payload);
616 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
617 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
621 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
622 SILC_STATUS_ERR_TOO_MANY_PARAMS);
626 /* Get destination ID */
627 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
629 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
630 SILC_STATUS_ERR_NO_CLIENT_ID);
633 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
636 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
638 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
639 SILC_STATUS_ERR_NO_CHANNEL_ID);
642 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
644 /* Check whether the channel exists */
645 channel = silc_idlist_find_channel_by_id(server->local_list->channels,
648 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
649 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
653 /* Check whether the sender of this command is on the channel. */
654 sender = (SilcClientList *)sock->user_data;
655 if (!silc_server_client_on_channel(sender, channel)) {
656 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
657 SILC_STATUS_ERR_NOT_ON_CHANNEL);
661 /* Check whether the channel is invite-only channel. If yes then the
662 sender of this command must be at least channel operator. */
665 /* Check whether the requested client is already on the channel. */
666 /* XXX if we are normal server we don't know about global clients on
667 the channel thus we must request it (NAMES command), check from
668 local cache as well. */
670 /* Find the connection data for the destination. If it is local we will
671 send it directly otherwise we will send it to router for routing. */
672 dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
674 dest_sock = (SilcSocketConnection)dest->connection;
676 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
678 /* Send notify to the client that is invited to the channel */
679 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
680 "%s invites you to channel %s",
681 sender->nickname, channel->channel_name);
683 /* Send command reply */
684 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
688 silc_server_command_free(cmd);
691 /* Quits connection to client. This gets called if client won't
692 close the connection even when it has issued QUIT command. */
694 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
696 SilcServer server = (SilcServer)context;
697 SilcSocketConnection sock = server->sockets[fd];
699 /* Free all client specific data, such as client entry and entires
700 on channels this client may be on. */
701 silc_server_free_sock_user_data(server, sock);
703 /* Close the connection on our side */
704 silc_server_close_connection(server, sock);
707 /* Quits SILC session. This is the normal way to disconnect client. */
709 SILC_SERVER_CMD_FUNC(quit)
711 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
712 SilcServer server = cmd->server;
713 SilcSocketConnection sock = cmd->sock;
715 SILC_LOG_DEBUG(("Start"));
717 /* We quit the connection with little timeout */
718 silc_task_register(server->timeout_queue, sock->sock,
719 silc_server_command_quit_cb, server,
720 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
722 silc_server_command_free(cmd);
725 SILC_SERVER_CMD_FUNC(kill)
729 SILC_SERVER_CMD_FUNC(info)
733 SILC_SERVER_CMD_FUNC(connect)
737 /* Server side of command PING. This just replies to the ping. */
739 SILC_SERVER_CMD_FUNC(ping)
741 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
742 SilcServer server = cmd->server;
745 unsigned char *id_string;
747 argc = silc_command_get_arg_num(cmd->payload);
749 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
750 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
754 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
755 SILC_STATUS_ERR_TOO_MANY_PARAMS);
760 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
762 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
763 SILC_STATUS_ERR_NO_SERVER_ID);
766 id = silc_id_str2id(id_string, SILC_ID_SERVER);
768 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
770 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
773 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
774 SILC_STATUS_ERR_NO_SUCH_SERVER);
781 silc_server_command_free(cmd);
784 SILC_SERVER_CMD_FUNC(oper)
793 SilcChannelList *channel;
795 } JoinInternalContext;
797 SILC_TASK_CALLBACK(silc_server_command_join_notify)
799 JoinInternalContext *ctx = (JoinInternalContext *)context;
801 if (ctx->channel->key && ctx->channel->key_len) {
802 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
803 "%s (%s@%s) has joined channel %s",
804 ctx->nickname, ctx->username,
805 ctx->hostname, ctx->channel_name);
808 silc_task_register(ctx->server->timeout_queue, fd,
809 silc_server_command_join_notify, context,
810 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
814 /* Assembles NAMES command and executes it. This is called when client
815 joins to a channel and we wan't to send NAMES command reply to the
818 void silc_server_command_send_names(SilcServer server,
819 SilcSocketConnection sock,
820 SilcChannelList *channel)
822 SilcServerCommandContext cmd;
824 unsigned char *id_string;
826 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
827 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
828 1, id_string, SILC_ID_CHANNEL_LEN);
830 cmd = silc_calloc(1, sizeof(*cmd));
831 cmd->payload = silc_command_parse_payload(buffer);
832 cmd->server = server;
834 cmd->pending = FALSE;
836 silc_server_command_names((void *)cmd);
837 silc_free(id_string);
841 /* Server side of command JOIN. Joins client into requested channel. If
842 the channel does not exist it will be created. */
844 SILC_SERVER_CMD_FUNC(join)
846 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
847 SilcServer server = cmd->server;
848 SilcSocketConnection sock = cmd->sock;
849 SilcBuffer buffer = cmd->packet->buffer;
850 int argc, i, tmp_len;
851 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
852 unsigned char *passphrase, mode[4];
853 SilcChannelList *channel;
854 SilcServerID *router_id;
855 SilcIDCache *id_cache;
857 SilcClientList *client;
859 SILC_LOG_DEBUG(("Start"));
861 #define LCC(x) server->local_list->channel_cache[(x) - 32]
862 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
864 /* Check number of parameters */
865 argc = silc_command_get_arg_num(cmd->payload);
867 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
868 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
872 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
873 SILC_STATUS_ERR_TOO_MANY_PARAMS);
877 /* Get channel name */
878 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
879 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
880 memcpy(channel_name, tmp, tmp_len);
881 if (silc_server_command_bad_chars(tmp) == TRUE) {
882 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
883 SILC_STATUS_ERR_BAD_CHANNEL);
884 silc_free(channel_name);
889 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
891 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
892 memcpy(passphrase, tmp, tmp_len);
895 /* Get cipher name */
896 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
898 /* See if the channel exists */
899 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
900 channel_name, &id_cache) == FALSE) {
901 /* Channel not found */
904 /* If we are standalone server we don't have a router, we just create
905 the channel by ourselves. */
906 if (server->standalone) {
907 router_id = server->id;
908 channel = silc_server_new_channel(server, router_id,
909 cipher, channel_name);
913 /* No channel ID found, the channel does not exist on our server.
914 We send JOIN command to our router which will handle the joining
915 procedure (either creates the channel if it doesn't exist or
916 joins the client to it) - if we are normal server. */
917 if (server->server_type == SILC_SERVER) {
919 /* Forward the original JOIN command to the router */
920 silc_buffer_push(buffer, buffer->data - buffer->head);
921 silc_server_packet_forward(server, (SilcSocketConnection)
922 server->id_entry->router->connection,
923 buffer->data, buffer->len, TRUE);
925 /* Add the command to be pending. It will be re-executed after
926 router has replied back to us. */
928 silc_server_command_pending(SILC_COMMAND_JOIN,
929 silc_server_command_join, context);
934 /* If we are router and the channel does not exist we will check our
935 global list for the channel. */
936 if (!id_cache && server->server_type == SILC_ROUTER) {
938 /* Notify all routers about the new channel in SILC network. */
939 if (!server->standalone) {
941 silc_server_send_new_id(server, server->id_entry->router->connection,
943 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
949 channel = (SilcChannelList *)id_cache->context;
953 /* XXX must check whether the client already is on the channel */
955 /* Join the client to the channel */
956 i = channel->user_list_count;
957 channel->user_list = silc_realloc(channel->user_list,
958 sizeof(*channel->user_list) * (i + 1));
959 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
961 /* If the JOIN request was forwarded to us we will make a bit slower
962 query to get the client pointer. Otherwise, we get the client pointer
964 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
965 client = (SilcClientList *)sock->user_data;
966 channel->user_list[i].client = client;
968 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
969 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
970 channel->user_list[i].client = client;
973 channel->user_list_count++;
975 i = client->channel_count;
976 client->channel = silc_realloc(client->channel,
977 sizeof(*client->channel) * (i + 1));
978 client->channel[i] = channel;
979 client->channel_count++;
981 /* Notify router about new user on channel. If we are normal server
982 we send it to our router, if we are router we send it to our
984 if (!server->standalone) {
988 /* Send command reply to the client. Client receives the Channe ID,
989 channel mode and possibly other information in this reply packet. */
991 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
992 SILC_PUT32_MSB(channel->mode, mode);
996 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
999 strlen(channel_name),
1000 3, id_string, SILC_ID_CHANNEL_LEN,
1004 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1007 strlen(channel_name),
1008 3, id_string, SILC_ID_CHANNEL_LEN,
1011 strlen(channel->topic));
1013 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1014 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1015 silc_server_packet_send_dest(cmd->server, cmd->sock,
1016 SILC_PACKET_COMMAND_REPLY, 0,
1017 id, cmd->packet->src_id_type,
1018 packet->data, packet->len, FALSE);
1021 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1022 packet->data, packet->len, FALSE);
1024 silc_buffer_free(packet);
1027 /* Send channel key to the client. Client cannot start transmitting
1028 to the channel until we have sent the key. */
1029 if (!cmd->pending) {
1030 tmp_len = strlen(channel->channel_key->cipher->name);
1032 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1034 channel->channel_key->cipher->name,
1035 channel->key_len / 8, channel->key);
1037 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1038 packet->data, packet->len, FALSE);
1039 silc_buffer_free(packet);
1043 silc_free(id_string);
1045 /* Finally, send notify message to all clients on the channel about
1046 new user on the channel. */
1047 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1048 if (!cmd->pending) {
1049 silc_server_send_notify_to_channel(server, channel,
1050 "%s (%s@%s) has joined channel %s",
1051 client->nickname, client->username,
1052 sock->hostname ? sock->hostname :
1053 sock->ip, channel_name);
1055 /* This is pending command request. Send the notify after we have
1056 received the key for the channel from the router. */
1057 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1058 ctx->channel_name = channel_name;
1059 ctx->nickname = client->nickname;
1060 ctx->username = client->username;
1061 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1062 ctx->channel = channel;
1063 ctx->server = server;
1064 silc_task_register(server->timeout_queue, sock->sock,
1065 silc_server_command_join_notify, ctx,
1066 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1070 /* Send NAMES command reply to the joined channel so the user sees who
1071 is currently on the channel. */
1072 silc_server_command_send_names(server, sock, channel);
1075 silc_server_command_free(cmd);
1080 /* Server side of command MOTD. Sends servers current "message of the
1081 day" to the client. */
1083 SILC_SERVER_CMD_FUNC(motd)
1086 SILC_LOG_DEBUG(("Start"));
1090 SILC_SERVER_CMD_FUNC(umode)
1094 SILC_SERVER_CMD_FUNC(cmode)
1098 SILC_SERVER_CMD_FUNC(kick)
1102 SILC_SERVER_CMD_FUNC(restart)
1106 SILC_SERVER_CMD_FUNC(close)
1110 SILC_SERVER_CMD_FUNC(die)
1114 SILC_SERVER_CMD_FUNC(silcoper)
1118 /* Server side command of LEAVE. Removes client from a channel. */
1120 SILC_SERVER_CMD_FUNC(leave)
1122 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1123 SilcServer server = cmd->server;
1124 SilcSocketConnection sock = cmd->sock;
1125 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1127 SilcChannelList *channel;
1129 unsigned int i, argc, key_len;
1130 unsigned char *tmp, channel_key[32];
1132 SILC_LOG_DEBUG(("Start"));
1134 argc = silc_command_get_arg_num(cmd->payload);
1136 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1137 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1141 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1142 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1146 /* Get Channel ID */
1147 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1149 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1150 SILC_STATUS_ERR_NO_CHANNEL_ID);
1153 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1155 /* Get channel entry */
1156 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1158 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1159 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1163 /* Check whether this client is on the channel */
1164 if (!silc_server_client_on_channel(id_entry, channel)) {
1165 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1166 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1170 /* Remove client from channel */
1171 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1172 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1175 /* If the channel does not exist anymore we won't send anything */
1179 /* Re-generate channel key */
1180 key_len = channel->key_len / 8;
1181 for (i = 0; i < key_len; i++)
1182 channel_key[i] = silc_rng_get_byte(server->rng);
1183 channel->channel_key->cipher->set_key(channel->channel_key->context,
1184 channel_key, key_len);
1185 memset(channel->key, 0, key_len);
1186 silc_free(channel->key);
1187 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1188 memcpy(channel->key, channel_key, key_len);
1189 memset(channel_key, 0, sizeof(channel_key));
1191 /* Encode channel key payload to be distributed on the channel */
1193 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1194 strlen(channel->channel_key->cipher->name),
1195 channel->channel_key->cipher->name,
1196 key_len, channel->key);
1198 /* If we are normal server then we will send it to our router. If we
1199 are router we will send it to all local servers that has clients on
1201 if (server->server_type == SILC_SERVER) {
1202 if (!server->standalone)
1203 silc_server_packet_send(server,
1204 cmd->server->id_entry->router->connection,
1205 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1211 /* Send to locally connected clients on the channel */
1212 silc_server_packet_send_local_channel(server, channel,
1213 SILC_PACKET_CHANNEL_KEY, 0,
1214 packet->data, packet->len, FALSE);
1216 silc_buffer_free(packet);
1220 silc_server_command_free(cmd);
1223 /* Server side of command NAMES. Resolves clients and their names currently
1224 joined on the requested channel. The name list is sent back to the
1227 SILC_SERVER_CMD_FUNC(names)
1229 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1230 SilcServer server = cmd->server;
1231 SilcChannelList *channel;
1234 unsigned int i, len, len2, argc;
1236 char *name_list = NULL, *n;
1237 SilcBuffer client_id_list;
1239 SILC_LOG_DEBUG(("Start"));
1241 argc = silc_command_get_arg_num(cmd->payload);
1243 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1244 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1248 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1249 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1253 /* Get Channel ID */
1254 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1256 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1257 SILC_STATUS_ERR_NO_CHANNEL_ID);
1260 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1262 /* Check whether the channel exists. If we are normal server and the
1263 channel does not exist we will send this same command to our router
1264 which will know if the channel exists. */
1265 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1267 if (server->server_type == SILC_SERVER && !server->standalone) {
1268 /* XXX Send names command */
1270 cmd->pending = TRUE;
1271 silc_server_command_pending(SILC_COMMAND_NAMES,
1272 silc_server_command_names, context);
1276 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1277 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1281 /* Assemble the name list now */
1284 for (i = 0; i < channel->user_list_count; i++) {
1285 if (!channel->user_list[i].client)
1288 n = channel->user_list[i].client->nickname;
1292 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1293 memcpy(name_list + (len - len2), n, len2);
1296 if (i == channel->user_list_count - 1)
1298 memcpy(name_list + len, ",", 1);
1303 /* Assemble the Client ID list now */
1304 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1305 channel->user_list_count);
1306 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1307 channel->user_list_count));
1308 for (i = 0; i < channel->user_list_count; i++) {
1309 unsigned char *id_string;
1311 if (!channel->user_list[i].client)
1314 id_string = silc_id_id2str(channel->user_list[i].client->id,
1316 silc_buffer_format(client_id_list,
1317 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1319 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1320 silc_free(id_string);
1322 silc_buffer_push(client_id_list,
1323 client_id_list->data - client_id_list->head);
1326 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1328 2, tmp, SILC_ID_CHANNEL_LEN,
1331 4, client_id_list->data,
1332 client_id_list->len);
1333 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1334 packet->data, packet->len, FALSE);
1336 silc_buffer_free(packet);
1337 silc_free(name_list);
1338 silc_buffer_free(client_id_list);
1342 silc_server_command_free(cmd);