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.7 2000/07/07 06:55:24 priikone
24 * Do not allow client to join twice on same channel.
26 * Revision 1.6 2000/07/06 10:20:59 priikone
27 * Cipher name in joining is not mandatory, removed check.
29 * Revision 1.5 2000/07/06 07:16:43 priikone
30 * Fixed a wrong way of sending command replies. The fixed way
31 * does comply with the protocol.
33 * Revision 1.4 2000/07/05 06:13:38 priikone
34 * Added PING, INVITE and NAMES command.
36 * Revision 1.3 2000/07/03 05:52:22 priikone
37 * Implemented LEAVE command.
39 * Revision 1.2 2000/06/28 05:06:38 priikone
40 * Shorter timeout for channel joining notify.
42 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
43 * Imported from internal CVS/Added Log headers.
48 #include "serverincludes.h"
49 #include "server_internal.h"
51 /* Server command list. */
52 SilcServerCommand silc_command_list[] =
54 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
55 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
56 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
57 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
58 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
59 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
60 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
61 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
62 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
63 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
64 SILC_SERVER_CMD(connect, CONNECT,
65 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
66 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
67 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
68 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
69 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
70 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
71 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
72 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
73 SILC_SERVER_CMD(restart, RESTART,
74 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
75 SILC_SERVER_CMD(close, CLOSE,
76 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
77 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
78 SILC_SERVER_CMD(silcoper, SILCOPER,
79 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
80 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
81 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
86 /* List of pending commands. */
87 SilcServerCommandPending *silc_command_pending = NULL;
89 /* Add new pending command to the list of pending commands. Currently
90 pending commands are executed from command replies, thus we can
91 execute any command after receiving some specific command reply.
93 The argument `reply_cmd' is the command reply from where the callback
94 function is to be called, thus, it IS NOT the command to be executed. */
96 void silc_server_command_pending(SilcCommand reply_cmd,
97 SilcCommandCb callback,
100 SilcServerCommandPending *reply, *r;
102 reply = silc_calloc(1, sizeof(*reply));
103 reply->reply_cmd = reply_cmd;
104 reply->context = context;
105 reply->callback = callback;
107 if (silc_command_pending == NULL) {
108 silc_command_pending = reply;
112 for (r = silc_command_pending; r; r = r->next) {
113 if (r->next == NULL) {
120 /* Deletes pending command by reply command type. */
122 void silc_server_command_pending_del(SilcCommand reply_cmd)
124 SilcServerCommandPending *r, *tmp;
126 if (silc_command_pending) {
127 if (silc_command_pending->reply_cmd == reply_cmd) {
128 silc_free(silc_command_pending);
129 silc_command_pending = NULL;
133 for (r = silc_command_pending; r; r = r->next) {
134 if (r->next && r->next->reply_cmd == reply_cmd) {
136 r->next = r->next->next;
144 /* Free's the command context allocated before executing the command */
146 static void silc_server_command_free(SilcServerCommandContext cmd)
149 silc_command_free_payload(cmd->payload);
154 #define SILC_COMMAND_STATUS_DATA(x) \
157 /* Sends simple status message as command reply packet */
160 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
162 SilcCommandStatus status)
166 SILC_LOG_DEBUG(("Sending command status %d", status));
168 buffer = silc_command_encode_reply_payload_va(command, status, 0);
169 silc_server_packet_send(cmd->server, cmd->sock,
170 SILC_PACKET_COMMAND_REPLY, 0,
171 buffer->data, buffer->len, FALSE);
172 silc_buffer_free(buffer);
175 /* Sends command status reply with one extra argument. The argument
176 type must be sent as argument. */
179 silc_server_command_send_status_data(SilcServerCommandContext cmd,
181 SilcCommandStatus status,
182 unsigned int arg_type,
184 unsigned int arg_len)
188 SILC_LOG_DEBUG(("Sending command status %d", status));
190 buffer = silc_command_encode_reply_payload_va(command, status, 1,
191 arg_type, arg, arg_len);
192 silc_server_packet_send(cmd->server, cmd->sock,
193 SILC_PACKET_COMMAND_REPLY, 0,
194 buffer->data, buffer->len, FALSE);
195 silc_buffer_free(buffer);
198 /* Server side of command WHOIS. Processes user's query and sends found
199 results as command replies back to the client. */
201 SILC_SERVER_CMD_FUNC(whois)
203 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
204 char *tmp, *nick = NULL, *server = NULL;
205 unsigned int argc, count = 0, len;
206 SilcClientList *entry;
208 unsigned char *id_string;
210 SILC_LOG_DEBUG(("Start"));
212 argc = silc_command_get_arg_num(cmd->payload);
214 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
215 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
219 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
220 SILC_STATUS_ERR_TOO_MANY_PARAMS);
224 /* Get the nickname@server string and parse it. */
225 tmp = silc_command_get_first_arg(cmd->payload, NULL);
227 if (strchr(tmp, '@')) {
228 len = strcspn(tmp, "@");
229 nick = silc_calloc(len + 1, sizeof(char));
230 memcpy(nick, tmp, len);
231 server = silc_calloc(strlen(tmp) - len, sizeof(char));
232 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
237 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
238 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
242 /* Get the max count of reply messages allowed */
244 tmp = silc_command_get_next_arg(cmd->payload, NULL);
246 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
247 SILC_STATUS_ERR_TOO_MANY_PARAMS);
257 /* Then, make the query from our local client list */
258 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
262 /* If we are normal server and are connected to a router we will
263 make global query from the router. */
264 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
269 /* If we are router then we will check our global list as well. */
270 if (cmd->server->server_type == SILC_ROUTER) {
272 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
275 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
276 SILC_STATUS_ERR_NO_SUCH_NICK,
277 3, tmp, strlen(tmp));
283 silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
284 SILC_STATUS_ERR_NO_SUCH_NICK,
285 3, tmp, strlen(tmp));
290 /* XXX, works only for local server info */
292 /* Send WHOIS reply */
293 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
294 tmp = silc_command_get_first_arg(cmd->payload, NULL);
297 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
298 char nh[256], uh[256];
299 SilcSocketConnection hsock;
301 memset(uh, 0, sizeof(uh));
302 memset(nh, 0, sizeof(nh));
304 strncat(nh, entry->nickname, strlen(entry->nickname));
306 len = entry->router ? strlen(entry->router->server_name) :
307 strlen(cmd->server->server_name);
308 strncat(nh, entry->router ? entry->router->server_name :
309 cmd->server->server_name, len);
311 strncat(uh, entry->username, strlen(entry->username));
313 hsock = (SilcSocketConnection)entry->connection;
314 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
315 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
320 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
322 2, id_string, SILC_ID_CLIENT_LEN,
326 strlen(entry->userinfo));
329 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
331 2, id_string, SILC_ID_CLIENT_LEN,
338 silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
340 2, id_string, SILC_ID_CLIENT_LEN,
342 strlen(entry->nickname),
343 4, tmp, strlen(tmp)); /* XXX */
345 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
346 0, packet->data, packet->len, FALSE);
348 silc_free(id_string);
349 silc_buffer_free(packet);
352 silc_server_command_free(cmd);
355 SILC_SERVER_CMD_FUNC(whowas)
359 SILC_SERVER_CMD_FUNC(identify)
361 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
362 char *tmp, *nick = NULL, *server = NULL;
363 unsigned int argc, count = 0, len;
364 SilcClientList *entry; SilcBuffer packet;
365 unsigned char *id_string;
367 SILC_LOG_DEBUG(("Start"));
369 argc = silc_command_get_arg_num(cmd->payload);
371 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
372 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
376 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
377 SILC_STATUS_ERR_TOO_MANY_PARAMS);
381 /* Get the nickname@server string and parse it. */
382 tmp = silc_command_get_first_arg(cmd->payload, NULL);
384 if (strchr(tmp, '@')) {
385 len = strcspn(tmp, "@");
386 nick = silc_calloc(len + 1, sizeof(char));
387 memcpy(nick, tmp, len);
388 server = silc_calloc(strlen(tmp) - len, sizeof(char));
389 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
394 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
395 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
399 /* Get the max count of reply messages allowed */
401 tmp = silc_command_get_next_arg(cmd->payload, NULL);
403 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
404 SILC_STATUS_ERR_TOO_MANY_PARAMS);
410 /* Then, make the query from our local client list */
411 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
412 nick, cmd->server->md5hash);
415 /* If we are normal server and are connected to a router we will
416 make global query from the router. */
417 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
418 SilcBuffer buffer = cmd->packet->buffer;
420 /* Send IDENTIFY command to our router */
421 silc_buffer_push(buffer, buffer->data - buffer->head);
422 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
423 cmd->server->id_entry->router->connection,
424 buffer->data, buffer->len, TRUE);
428 /* If we are router then we will check our global list as well. */
429 if (cmd->server->server_type == SILC_ROUTER) {
431 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
432 nick, cmd->server->md5hash);
434 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
435 SILC_STATUS_ERR_NO_SUCH_NICK,
436 3, tmp, strlen(tmp));
442 silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
443 SILC_STATUS_ERR_NO_SUCH_NICK,
444 3, tmp, strlen(tmp));
449 /* Send IDENTIFY reply */
450 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
451 tmp = silc_command_get_first_arg(cmd->payload, NULL);
452 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
456 3, nick, strlen(nick));
458 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
459 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
460 silc_server_packet_send_dest(cmd->server, cmd->sock,
461 SILC_PACKET_COMMAND_REPLY, 0,
462 id, cmd->packet->src_id_type,
463 packet->data, packet->len, FALSE);
467 silc_server_packet_send(cmd->server, cmd->sock,
468 SILC_PACKET_COMMAND_REPLY, 0,
469 packet->data, packet->len, FALSE);
471 silc_free(id_string);
472 silc_buffer_free(packet);
479 silc_server_command_free(cmd);
482 /* Checks string for bad characters and returns TRUE if they are found. */
484 static int silc_server_command_bad_chars(char *nick)
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;
491 if (strchr(nick, '*')) return TRUE;
492 if (strchr(nick, '/')) return TRUE;
493 if (strchr(nick, '@')) return TRUE;
498 /* Server side of command NICK. Sets nickname for user. Setting
499 nickname causes generation of a new client ID for the client. The
500 new client ID is sent to the client after changing the nickname. */
502 SILC_SERVER_CMD_FUNC(nick)
504 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
505 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
506 SilcServer server = cmd->server;
508 SilcClientID *new_id;
512 SILC_LOG_DEBUG(("Start"));
514 #define LCC(x) server->local_list->client_cache[(x) - 32]
515 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
517 /* Check number of arguments */
518 if (silc_command_get_arg_num(cmd->payload) < 1) {
519 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
520 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
525 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
526 if (silc_server_command_bad_chars(nick) == TRUE) {
527 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
528 SILC_STATUS_ERR_BAD_NICKNAME);
532 /* Create new Client ID */
533 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
534 cmd->server->md5hash, nick,
537 /* Send notify about nickname change to our router. We send the new
538 ID and ask to replace it with the old one. */
539 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
540 silc_server_send_replace_id(server, server->id_entry->router->connection,
542 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
543 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
545 /* If we are router we have to distribute the new Client ID to all
547 if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
548 silc_server_send_replace_id(server, server->id_entry->router->connection,
550 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
551 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
553 /* Remove old cache entry */
554 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
555 LCCC(id_entry->nickname[0]),
556 SILC_ID_CLIENT, id_entry->id);
560 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
561 silc_free(id_entry->id);
564 /* Save the nickname as this client is our local client */
565 if (id_entry->nickname)
566 silc_free(id_entry->nickname);
568 id_entry->nickname = strdup(nick);
569 id_entry->id = new_id;
571 /* Update client cache */
572 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
573 id_entry->nickname, SILC_ID_CLIENT,
574 id_entry->id, (void *)id_entry);
576 /* Send the new Client ID as reply command back to client */
577 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
578 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NICK,
582 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
583 0, packet->data, packet->len, FALSE);
585 silc_free(id_string);
586 silc_buffer_free(packet);
589 silc_server_command_free(cmd);
594 SILC_SERVER_CMD_FUNC(list)
598 SILC_SERVER_CMD_FUNC(topic)
602 /* Server side of INVITE command. Invites some client to join some channel. */
604 SILC_SERVER_CMD_FUNC(invite)
606 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
607 SilcServer server = cmd->server;
608 SilcSocketConnection sock = cmd->sock, dest_sock;
609 SilcClientList *sender, *dest;
610 SilcClientID *dest_id;
611 SilcChannelList *channel;
612 SilcChannelID *channel_id;
613 unsigned int argc, len;
614 unsigned char *id_string;
616 /* Check number of arguments */
617 argc = silc_command_get_arg_num(cmd->payload);
619 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
620 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
624 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
625 SILC_STATUS_ERR_TOO_MANY_PARAMS);
629 /* Get destination ID */
630 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
632 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
633 SILC_STATUS_ERR_NO_CLIENT_ID);
636 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
639 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
641 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
642 SILC_STATUS_ERR_NO_CHANNEL_ID);
645 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
647 /* Check whether the channel exists */
648 channel = silc_idlist_find_channel_by_id(server->local_list->channels,
651 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
652 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
656 /* Check whether the sender of this command is on the channel. */
657 sender = (SilcClientList *)sock->user_data;
658 if (!silc_server_client_on_channel(sender, channel)) {
659 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
660 SILC_STATUS_ERR_NOT_ON_CHANNEL);
664 /* Check whether the channel is invite-only channel. If yes then the
665 sender of this command must be at least channel operator. */
668 /* Check whether the requested client is already on the channel. */
669 /* XXX if we are normal server we don't know about global clients on
670 the channel thus we must request it (NAMES command), check from
671 local cache as well. */
673 /* Find the connection data for the destination. If it is local we will
674 send it directly otherwise we will send it to router for routing. */
675 dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
677 dest_sock = (SilcSocketConnection)dest->connection;
679 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
681 /* Send notify to the client that is invited to the channel */
682 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
683 "%s invites you to channel %s",
684 sender->nickname, channel->channel_name);
686 /* Send command reply */
687 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
691 silc_server_command_free(cmd);
694 /* Quits connection to client. This gets called if client won't
695 close the connection even when it has issued QUIT command. */
697 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
699 SilcServer server = (SilcServer)context;
700 SilcSocketConnection sock = server->sockets[fd];
702 /* Free all client specific data, such as client entry and entires
703 on channels this client may be on. */
704 silc_server_free_sock_user_data(server, sock);
706 /* Close the connection on our side */
707 silc_server_close_connection(server, sock);
710 /* Quits SILC session. This is the normal way to disconnect client. */
712 SILC_SERVER_CMD_FUNC(quit)
714 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
715 SilcServer server = cmd->server;
716 SilcSocketConnection sock = cmd->sock;
718 SILC_LOG_DEBUG(("Start"));
720 /* We quit the connection with little timeout */
721 silc_task_register(server->timeout_queue, sock->sock,
722 silc_server_command_quit_cb, server,
723 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
725 silc_server_command_free(cmd);
728 SILC_SERVER_CMD_FUNC(kill)
732 SILC_SERVER_CMD_FUNC(info)
736 SILC_SERVER_CMD_FUNC(connect)
740 /* Server side of command PING. This just replies to the ping. */
742 SILC_SERVER_CMD_FUNC(ping)
744 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
745 SilcServer server = cmd->server;
748 unsigned char *id_string;
750 argc = silc_command_get_arg_num(cmd->payload);
752 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
753 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
757 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
758 SILC_STATUS_ERR_TOO_MANY_PARAMS);
763 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
765 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
766 SILC_STATUS_ERR_NO_SERVER_ID);
769 id = silc_id_str2id(id_string, SILC_ID_SERVER);
771 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
773 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
776 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
777 SILC_STATUS_ERR_NO_SUCH_SERVER);
784 silc_server_command_free(cmd);
787 SILC_SERVER_CMD_FUNC(oper)
796 SilcChannelList *channel;
798 } JoinInternalContext;
800 SILC_TASK_CALLBACK(silc_server_command_join_notify)
802 JoinInternalContext *ctx = (JoinInternalContext *)context;
804 if (ctx->channel->key && ctx->channel->key_len) {
805 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
806 "%s (%s@%s) has joined channel %s",
807 ctx->nickname, ctx->username,
808 ctx->hostname, ctx->channel_name);
811 silc_task_register(ctx->server->timeout_queue, fd,
812 silc_server_command_join_notify, context,
813 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
817 /* Assembles NAMES command and executes it. This is called when client
818 joins to a channel and we wan't to send NAMES command reply to the
821 void silc_server_command_send_names(SilcServer server,
822 SilcSocketConnection sock,
823 SilcChannelList *channel)
825 SilcServerCommandContext cmd;
827 unsigned char *id_string;
829 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
830 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
831 1, id_string, SILC_ID_CHANNEL_LEN);
833 cmd = silc_calloc(1, sizeof(*cmd));
834 cmd->payload = silc_command_parse_payload(buffer);
835 cmd->server = server;
837 cmd->pending = FALSE;
839 silc_server_command_names((void *)cmd);
840 silc_free(id_string);
844 /* Server side of command JOIN. Joins client into requested channel. If
845 the channel does not exist it will be created. */
847 SILC_SERVER_CMD_FUNC(join)
849 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
850 SilcServer server = cmd->server;
851 SilcSocketConnection sock = cmd->sock;
852 SilcBuffer buffer = cmd->packet->buffer;
853 int argc, i, tmp_len;
854 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
855 unsigned char *passphrase, mode[4];
856 SilcChannelList *channel;
857 SilcServerID *router_id;
858 SilcIDCache *id_cache;
860 SilcClientList *client;
862 SILC_LOG_DEBUG(("Start"));
864 #define LCC(x) server->local_list->channel_cache[(x) - 32]
865 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
867 /* Check number of parameters */
868 argc = silc_command_get_arg_num(cmd->payload);
870 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
871 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
875 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
876 SILC_STATUS_ERR_TOO_MANY_PARAMS);
880 /* Get channel name */
881 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
882 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
883 memcpy(channel_name, tmp, tmp_len);
884 if (silc_server_command_bad_chars(tmp) == TRUE) {
885 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
886 SILC_STATUS_ERR_BAD_CHANNEL);
887 silc_free(channel_name);
892 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
894 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
895 memcpy(passphrase, tmp, tmp_len);
898 /* Get cipher name */
899 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
901 /* See if the channel exists */
902 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
903 channel_name, &id_cache) == FALSE) {
904 /* Channel not found */
907 /* If we are standalone server we don't have a router, we just create
908 the channel by ourselves. */
909 if (server->standalone) {
910 router_id = server->id;
911 channel = silc_server_new_channel(server, router_id,
912 cipher, channel_name);
916 /* No channel ID found, the channel does not exist on our server.
917 We send JOIN command to our router which will handle the joining
918 procedure (either creates the channel if it doesn't exist or
919 joins the client to it) - if we are normal server. */
920 if (server->server_type == SILC_SERVER) {
922 /* Forward the original JOIN command to the router */
923 silc_buffer_push(buffer, buffer->data - buffer->head);
924 silc_server_packet_forward(server, (SilcSocketConnection)
925 server->id_entry->router->connection,
926 buffer->data, buffer->len, TRUE);
928 /* Add the command to be pending. It will be re-executed after
929 router has replied back to us. */
931 silc_server_command_pending(SILC_COMMAND_JOIN,
932 silc_server_command_join, context);
937 /* If we are router and the channel does not exist we will check our
938 global list for the channel. */
939 if (!id_cache && server->server_type == SILC_ROUTER) {
941 /* Notify all routers about the new channel in SILC network. */
942 if (!server->standalone) {
944 silc_server_send_new_id(server, server->id_entry->router->connection,
946 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
952 channel = (SilcChannelList *)id_cache->context;
956 /* If the JOIN request was forwarded to us we will make a bit slower
957 query to get the client pointer. Otherwise, we get the client pointer
959 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
960 client = (SilcClientList *)sock->user_data;
962 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
963 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
971 /* Check whether the client already is on the channel */
972 if (silc_server_client_on_channel(client, channel)) {
973 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
974 SILC_STATUS_ERR_USER_ON_CHANNEL);
975 silc_free(channel_name);
979 /* Join the client to the channel */
980 i = channel->user_list_count;
981 channel->user_list = silc_realloc(channel->user_list,
982 sizeof(*channel->user_list) * (i + 1));
983 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
984 channel->user_list[i].client = client;
985 channel->user_list_count++;
987 /* Add the channel to client's channel list */
988 i = client->channel_count;
989 client->channel = silc_realloc(client->channel,
990 sizeof(*client->channel) * (i + 1));
991 client->channel[i] = channel;
992 client->channel_count++;
994 /* Notify router about new user on channel. If we are normal server
995 we send it to our router, if we are router we send it to our
997 if (!server->standalone) {
1001 /* Send command reply to the client. Client receives the Channe ID,
1002 channel mode and possibly other information in this reply packet. */
1003 if (!cmd->pending) {
1004 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
1005 SILC_PUT32_MSB(channel->mode, mode);
1007 if (!channel->topic)
1009 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1012 strlen(channel_name),
1013 3, id_string, SILC_ID_CHANNEL_LEN,
1017 silc_command_encode_reply_payload_va(SILC_COMMAND_JOIN,
1020 strlen(channel_name),
1021 3, id_string, SILC_ID_CHANNEL_LEN,
1024 strlen(channel->topic));
1026 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1027 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1028 silc_server_packet_send_dest(cmd->server, cmd->sock,
1029 SILC_PACKET_COMMAND_REPLY, 0,
1030 id, cmd->packet->src_id_type,
1031 packet->data, packet->len, FALSE);
1034 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1035 packet->data, packet->len, FALSE);
1037 silc_buffer_free(packet);
1040 /* Send channel key to the client. Client cannot start transmitting
1041 to the channel until we have sent the key. */
1042 if (!cmd->pending) {
1043 tmp_len = strlen(channel->channel_key->cipher->name);
1045 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1047 channel->channel_key->cipher->name,
1048 channel->key_len / 8, channel->key);
1050 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1051 packet->data, packet->len, FALSE);
1052 silc_buffer_free(packet);
1056 silc_free(id_string);
1058 /* Finally, send notify message to all clients on the channel about
1059 new user on the channel. */
1060 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1061 if (!cmd->pending) {
1062 silc_server_send_notify_to_channel(server, channel,
1063 "%s (%s@%s) has joined channel %s",
1064 client->nickname, client->username,
1065 sock->hostname ? sock->hostname :
1066 sock->ip, channel_name);
1068 /* This is pending command request. Send the notify after we have
1069 received the key for the channel from the router. */
1070 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1071 ctx->channel_name = channel_name;
1072 ctx->nickname = client->nickname;
1073 ctx->username = client->username;
1074 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1075 ctx->channel = channel;
1076 ctx->server = server;
1077 silc_task_register(server->timeout_queue, sock->sock,
1078 silc_server_command_join_notify, ctx,
1079 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1083 /* Send NAMES command reply to the joined channel so the user sees who
1084 is currently on the channel. */
1085 silc_server_command_send_names(server, sock, channel);
1088 silc_server_command_free(cmd);
1093 /* Server side of command MOTD. Sends servers current "message of the
1094 day" to the client. */
1096 SILC_SERVER_CMD_FUNC(motd)
1099 SILC_LOG_DEBUG(("Start"));
1103 SILC_SERVER_CMD_FUNC(umode)
1107 SILC_SERVER_CMD_FUNC(cmode)
1111 SILC_SERVER_CMD_FUNC(kick)
1115 SILC_SERVER_CMD_FUNC(restart)
1119 SILC_SERVER_CMD_FUNC(close)
1123 SILC_SERVER_CMD_FUNC(die)
1127 SILC_SERVER_CMD_FUNC(silcoper)
1131 /* Server side command of LEAVE. Removes client from a channel. */
1133 SILC_SERVER_CMD_FUNC(leave)
1135 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1136 SilcServer server = cmd->server;
1137 SilcSocketConnection sock = cmd->sock;
1138 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1140 SilcChannelList *channel;
1142 unsigned int i, argc, key_len;
1143 unsigned char *tmp, channel_key[32];
1145 SILC_LOG_DEBUG(("Start"));
1147 argc = silc_command_get_arg_num(cmd->payload);
1149 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1150 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1154 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1155 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1159 /* Get Channel ID */
1160 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1162 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1163 SILC_STATUS_ERR_NO_CHANNEL_ID);
1166 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1168 /* Get channel entry */
1169 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1171 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1172 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1176 /* Check whether this client is on the channel */
1177 if (!silc_server_client_on_channel(id_entry, channel)) {
1178 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1179 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1183 /* Remove client from channel */
1184 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1185 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1188 /* If the channel does not exist anymore we won't send anything */
1192 /* Re-generate channel key */
1193 key_len = channel->key_len / 8;
1194 for (i = 0; i < key_len; i++)
1195 channel_key[i] = silc_rng_get_byte(server->rng);
1196 channel->channel_key->cipher->set_key(channel->channel_key->context,
1197 channel_key, key_len);
1198 memset(channel->key, 0, key_len);
1199 silc_free(channel->key);
1200 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1201 memcpy(channel->key, channel_key, key_len);
1202 memset(channel_key, 0, sizeof(channel_key));
1204 /* Encode channel key payload to be distributed on the channel */
1206 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1207 strlen(channel->channel_key->cipher->name),
1208 channel->channel_key->cipher->name,
1209 key_len, channel->key);
1211 /* If we are normal server then we will send it to our router. If we
1212 are router we will send it to all local servers that has clients on
1214 if (server->server_type == SILC_SERVER) {
1215 if (!server->standalone)
1216 silc_server_packet_send(server,
1217 cmd->server->id_entry->router->connection,
1218 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1224 /* Send to locally connected clients on the channel */
1225 silc_server_packet_send_local_channel(server, channel,
1226 SILC_PACKET_CHANNEL_KEY, 0,
1227 packet->data, packet->len, FALSE);
1229 silc_buffer_free(packet);
1233 silc_server_command_free(cmd);
1236 /* Server side of command NAMES. Resolves clients and their names currently
1237 joined on the requested channel. The name list is sent back to the
1240 SILC_SERVER_CMD_FUNC(names)
1242 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1243 SilcServer server = cmd->server;
1244 SilcChannelList *channel;
1247 unsigned int i, len, len2, argc;
1249 char *name_list = NULL, *n;
1250 SilcBuffer client_id_list;
1252 SILC_LOG_DEBUG(("Start"));
1254 argc = silc_command_get_arg_num(cmd->payload);
1256 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1257 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1261 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1262 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1266 /* Get Channel ID */
1267 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1269 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1270 SILC_STATUS_ERR_NO_CHANNEL_ID);
1273 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1275 /* Check whether the channel exists. If we are normal server and the
1276 channel does not exist we will send this same command to our router
1277 which will know if the channel exists. */
1278 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1280 if (server->server_type == SILC_SERVER && !server->standalone) {
1281 /* XXX Send names command */
1283 cmd->pending = TRUE;
1284 silc_server_command_pending(SILC_COMMAND_NAMES,
1285 silc_server_command_names, context);
1289 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1290 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1294 /* Assemble the name list now */
1297 for (i = 0; i < channel->user_list_count; i++) {
1298 if (!channel->user_list[i].client)
1301 n = channel->user_list[i].client->nickname;
1305 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1306 memcpy(name_list + (len - len2), n, len2);
1309 if (i == channel->user_list_count - 1)
1311 memcpy(name_list + len, ",", 1);
1316 /* Assemble the Client ID list now */
1317 client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
1318 channel->user_list_count);
1319 silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
1320 channel->user_list_count));
1321 for (i = 0; i < channel->user_list_count; i++) {
1322 unsigned char *id_string;
1324 if (!channel->user_list[i].client)
1327 id_string = silc_id_id2str(channel->user_list[i].client->id,
1329 silc_buffer_format(client_id_list,
1330 SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
1332 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
1333 silc_free(id_string);
1335 silc_buffer_push(client_id_list,
1336 client_id_list->data - client_id_list->head);
1339 packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
1341 2, tmp, SILC_ID_CHANNEL_LEN,
1344 4, client_id_list->data,
1345 client_id_list->len);
1346 silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
1347 packet->data, packet->len, FALSE);
1349 silc_buffer_free(packet);
1350 silc_free(name_list);
1351 silc_buffer_free(client_id_list);
1355 silc_server_command_free(cmd);