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.4 2000/07/05 06:13:38 priikone
24 * Added PING, INVITE and NAMES command.
26 * Revision 1.3 2000/07/03 05:52:22 priikone
27 * Implemented LEAVE command.
29 * Revision 1.2 2000/06/28 05:06:38 priikone
30 * Shorter timeout for channel joining notify.
32 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
33 * Imported from internal CVS/Added Log headers.
38 #include "serverincludes.h"
39 #include "server_internal.h"
41 /* Server command list. */
42 SilcServerCommand silc_command_list[] =
44 SILC_SERVER_CMD(whois, WHOIS, SILC_CF_LAG | SILC_CF_REG),
45 SILC_SERVER_CMD(whowas, WHOWAS, SILC_CF_LAG | SILC_CF_REG),
46 SILC_SERVER_CMD(identify, IDENTIFY, SILC_CF_LAG | SILC_CF_REG),
47 SILC_SERVER_CMD(nick, NICK, SILC_CF_LAG | SILC_CF_REG),
48 SILC_SERVER_CMD(list, LIST, SILC_CF_LAG | SILC_CF_REG),
49 SILC_SERVER_CMD(topic, TOPIC, SILC_CF_LAG | SILC_CF_REG),
50 SILC_SERVER_CMD(invite, INVITE, SILC_CF_LAG | SILC_CF_REG),
51 SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
52 SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
53 SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
54 SILC_SERVER_CMD(connect, CONNECT,
55 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
56 SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
57 SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
58 SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG | SILC_CF_REG),
59 SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
60 SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
61 SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
62 SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
63 SILC_SERVER_CMD(restart, RESTART,
64 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
65 SILC_SERVER_CMD(close, CLOSE,
66 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
67 SILC_SERVER_CMD(die, DIE, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
68 SILC_SERVER_CMD(silcoper, SILCOPER,
69 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
70 SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG | SILC_CF_REG),
71 SILC_SERVER_CMD(names, NAMES, SILC_CF_LAG | SILC_CF_REG),
76 /* List of pending commands. */
77 SilcServerCommandPending *silc_command_pending = NULL;
79 /* Add new pending command to the list of pending commands. Currently
80 pending commands are executed from command replies, thus we can
81 execute any command after receiving some specific command reply.
83 The argument `reply_cmd' is the command reply from where the callback
84 function is to be called, thus, it IS NOT the command to be executed. */
86 void silc_server_command_pending(SilcCommand reply_cmd,
87 SilcCommandCb callback,
90 SilcServerCommandPending *reply, *r;
92 reply = silc_calloc(1, sizeof(*reply));
93 reply->reply_cmd = reply_cmd;
94 reply->context = context;
95 reply->callback = callback;
97 if (silc_command_pending == NULL) {
98 silc_command_pending = reply;
102 for (r = silc_command_pending; r; r = r->next) {
103 if (r->next == NULL) {
110 /* Deletes pending command by reply command type. */
112 void silc_server_command_pending_del(SilcCommand reply_cmd)
114 SilcServerCommandPending *r, *tmp;
116 if (silc_command_pending) {
117 if (silc_command_pending->reply_cmd == reply_cmd) {
118 silc_free(silc_command_pending);
119 silc_command_pending = NULL;
123 for (r = silc_command_pending; r; r = r->next) {
124 if (r->next && r->next->reply_cmd == reply_cmd) {
126 r->next = r->next->next;
134 /* Free's the command context allocated before executing the command */
136 static void silc_server_command_free(SilcServerCommandContext cmd)
139 silc_command_free_payload(cmd->payload);
144 /* Sends command status message as command reply packet. */
147 silc_server_command_send_status_msg(SilcServerCommandContext cmd,
149 SilcCommandStatus status,
151 unsigned int msg_len)
153 SilcBuffer sp_buf, buffer;
155 SILC_LOG_DEBUG(("Sending command status %d", status));
157 sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
158 buffer = silc_command_encode_payload_va(command, 1,
159 sp_buf->data, sp_buf->len);
160 silc_server_packet_send(cmd->server, cmd->sock,
161 SILC_PACKET_COMMAND_REPLY, 0,
162 buffer->data, buffer->len, FALSE);
163 silc_buffer_free(buffer);
164 silc_buffer_free(sp_buf);
167 /* Sends simple status message as command reply packet */
170 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
172 SilcCommandStatus status)
174 SilcBuffer sp_buf, buffer;
176 SILC_LOG_DEBUG(("Sending command status %d", status));
178 sp_buf = silc_command_encode_status_payload(status, NULL, 0);
179 buffer = silc_command_encode_payload_va(command, 1,
180 sp_buf->data, sp_buf->len);
181 silc_server_packet_send(cmd->server, cmd->sock,
182 SILC_PACKET_COMMAND_REPLY, 0,
183 buffer->data, buffer->len, FALSE);
184 silc_buffer_free(buffer);
185 silc_buffer_free(sp_buf);
188 /* Server side of command WHOIS. Processes user's query and sends found
189 results as command replies back to the client. */
191 SILC_SERVER_CMD_FUNC(whois)
193 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
194 char *tmp, *nick = NULL, *server = NULL;
195 unsigned int argc, count = 0, len;
196 SilcClientList *entry;
197 SilcBuffer sp_buf, packet;
198 unsigned char *id_string;
200 SILC_LOG_DEBUG(("Start"));
202 argc = silc_command_get_arg_num(cmd->payload);
204 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
205 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
209 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
210 SILC_STATUS_ERR_TOO_MANY_PARAMS);
214 /* Get the nickname@server string and parse it. */
215 tmp = silc_command_get_first_arg(cmd->payload, NULL);
217 if (strchr(tmp, '@')) {
218 len = strcspn(tmp, "@");
219 nick = silc_calloc(len + 1, sizeof(char));
220 memcpy(nick, tmp, len);
221 server = silc_calloc(strlen(tmp) - len, sizeof(char));
222 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
227 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
228 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
232 /* Get the max count of reply messages allowed */
234 tmp = silc_command_get_next_arg(cmd->payload, NULL);
236 silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
237 SILC_STATUS_ERR_TOO_MANY_PARAMS);
247 /* Then, make the query from our local client list */
248 entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
252 /* If we are normal server and are connected to a router we will
253 make global query from the router. */
254 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
259 /* If we are router then we will check our global list as well. */
260 if (cmd->server->server_type == SILC_ROUTER) {
262 silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
265 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
266 SILC_STATUS_ERR_NO_SUCH_NICK,
273 silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
274 SILC_STATUS_ERR_NO_SUCH_NICK,
280 /* XXX, works only for local server info */
282 /* Send WHOIS reply */
283 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
284 tmp = silc_command_get_first_arg(cmd->payload, NULL),
285 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
288 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
289 char nh[256], uh[256];
290 SilcSocketConnection hsock;
292 memset(uh, 0, sizeof(uh));
293 memset(nh, 0, sizeof(nh));
295 strncat(nh, entry->nickname, strlen(entry->nickname));
297 len = entry->router ? strlen(entry->router->server_name) :
298 strlen(cmd->server->server_name);
299 strncat(nh, entry->router ? entry->router->server_name :
300 cmd->server->server_name, len);
302 strncat(uh, entry->username, strlen(entry->username));
304 hsock = (SilcSocketConnection)entry->connection;
305 len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
306 strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
311 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5,
312 sp_buf->data, sp_buf->len,
313 id_string, SILC_ID_CLIENT_LEN,
317 strlen(entry->userinfo));
320 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
321 sp_buf->data, sp_buf->len,
322 id_string, SILC_ID_CLIENT_LEN,
329 silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
330 sp_buf->data, sp_buf->len,
331 id_string, SILC_ID_CLIENT_LEN,
332 entry->nickname, strlen(entry->nickname),
333 tmp, strlen(tmp)); /* XXX */
335 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
336 0, packet->data, packet->len, FALSE);
338 silc_free(id_string);
339 silc_buffer_free(packet);
343 silc_server_command_free(cmd);
346 SILC_SERVER_CMD_FUNC(whowas)
350 SILC_SERVER_CMD_FUNC(identify)
352 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
353 char *tmp, *nick = NULL, *server = NULL;
354 unsigned int argc, count = 0, len;
355 SilcClientList *entry; SilcBuffer sp_buf, packet;
356 unsigned char *id_string;
358 SILC_LOG_DEBUG(("Start"));
360 argc = silc_command_get_arg_num(cmd->payload);
362 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
363 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
367 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
368 SILC_STATUS_ERR_TOO_MANY_PARAMS);
372 /* Get the nickname@server string and parse it. */
373 tmp = silc_command_get_first_arg(cmd->payload, NULL);
375 if (strchr(tmp, '@')) {
376 len = strcspn(tmp, "@");
377 nick = silc_calloc(len + 1, sizeof(char));
378 memcpy(nick, tmp, len);
379 server = silc_calloc(strlen(tmp) - len, sizeof(char));
380 memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
385 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
386 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
390 /* Get the max count of reply messages allowed */
392 tmp = silc_command_get_next_arg(cmd->payload, NULL);
394 silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
395 SILC_STATUS_ERR_TOO_MANY_PARAMS);
401 /* Then, make the query from our local client list */
402 entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
403 nick, cmd->server->md5hash);
406 /* If we are normal server and are connected to a router we will
407 make global query from the router. */
408 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
409 SilcBuffer buffer = cmd->packet->buffer;
411 /* Send IDENTIFY command to our router */
412 silc_buffer_push(buffer, buffer->data - buffer->head);
413 silc_server_packet_forward(cmd->server, (SilcSocketConnection)
414 cmd->server->id_entry->router->connection,
415 buffer->data, buffer->len, TRUE);
419 /* If we are router then we will check our global list as well. */
420 if (cmd->server->server_type == SILC_ROUTER) {
422 silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
423 nick, cmd->server->md5hash);
425 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
426 SILC_STATUS_ERR_NO_SUCH_NICK,
433 silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
434 SILC_STATUS_ERR_NO_SUCH_NICK,
440 /* Send IDENTIFY reply */
441 id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
442 tmp = silc_command_get_first_arg(cmd->payload, NULL);
443 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
444 packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
445 sp_buf->data, sp_buf->len,
446 id_string, SILC_ID_CLIENT_LEN,
449 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
450 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
451 silc_server_packet_send_dest(cmd->server, cmd->sock,
452 SILC_PACKET_COMMAND_REPLY, 0,
453 id, cmd->packet->src_id_type,
454 packet->data, packet->len, FALSE);
458 silc_server_packet_send(cmd->server, cmd->sock,
459 SILC_PACKET_COMMAND_REPLY, 0,
460 packet->data, packet->len, FALSE);
462 silc_free(id_string);
463 silc_buffer_free(packet);
471 silc_server_command_free(cmd);
474 /* Checks string for bad characters and returns TRUE if they are found. */
476 static int silc_server_command_bad_chars(char *nick)
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;
484 if (strchr(nick, '/')) return TRUE;
485 if (strchr(nick, '@')) return TRUE;
490 /* Server side of command NICK. Sets nickname for user. Setting
491 nickname causes generation of a new client ID for the client. The
492 new client ID is sent to the client after changing the nickname. */
494 SILC_SERVER_CMD_FUNC(nick)
496 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
497 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
498 SilcServer server = cmd->server;
499 SilcBuffer packet, sp_buf;
500 SilcClientID *new_id;
504 SILC_LOG_DEBUG(("Start"));
506 #define LCC(x) server->local_list->client_cache[(x) - 32]
507 #define LCCC(x) server->local_list->client_cache_count[(x) - 32]
509 /* Check number of arguments */
510 if (silc_command_get_arg_num(cmd->payload) < 1) {
511 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
512 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
517 nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
518 if (silc_server_command_bad_chars(nick) == TRUE) {
519 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
520 SILC_STATUS_ERR_BAD_NICKNAME);
524 /* Create new Client ID */
525 silc_id_create_client_id(cmd->server->id, cmd->server->rng,
526 cmd->server->md5hash, nick,
529 /* Send notify about nickname change to our router. We send the new
530 ID and ask to replace it with the old one. */
531 if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
532 silc_server_send_replace_id(server, server->id_entry->router->connection,
534 SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
535 new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
537 /* If we are router we have to distribute the new Client ID to all
539 if (cmd->server->server_type == SILC_ROUTER && !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 /* Remove old cache entry */
546 silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
547 LCCC(id_entry->nickname[0]),
548 SILC_ID_CLIENT, id_entry->id);
552 memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
553 silc_free(id_entry->id);
556 /* Save the nickname as this client is our local client */
557 if (id_entry->nickname)
558 silc_free(id_entry->nickname);
560 id_entry->nickname = strdup(nick);
561 id_entry->id = new_id;
563 /* Update client cache */
564 LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
565 id_entry->nickname, SILC_ID_CLIENT,
566 id_entry->id, (void *)id_entry);
568 /* Send the new Client ID as reply command back to client */
569 id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
570 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
571 packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2,
572 sp_buf->data, sp_buf->len,
573 id_string, SILC_ID_CLIENT_LEN);
574 silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
575 0, packet->data, packet->len, FALSE);
577 silc_free(id_string);
578 silc_buffer_free(packet);
582 silc_server_command_free(cmd);
587 SILC_SERVER_CMD_FUNC(list)
591 SILC_SERVER_CMD_FUNC(topic)
595 /* Server side of INVITE command. Invites some client to join some channel. */
597 SILC_SERVER_CMD_FUNC(invite)
599 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
600 SilcServer server = cmd->server;
601 SilcSocketConnection sock = cmd->sock, dest_sock;
602 SilcClientList *sender, *dest;
603 SilcClientID *dest_id;
604 SilcChannelList *channel;
605 SilcChannelID *channel_id;
606 unsigned int argc, len;
607 unsigned char *id_string;
609 /* Check number of arguments */
610 argc = silc_command_get_arg_num(cmd->payload);
612 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
613 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
617 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
618 SILC_STATUS_ERR_TOO_MANY_PARAMS);
622 /* Get destination ID */
623 id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
625 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
626 SILC_STATUS_ERR_NO_CLIENT_ID);
629 dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
632 id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
634 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
635 SILC_STATUS_ERR_NO_CHANNEL_ID);
638 channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
640 /* Check whether the channel exists */
641 channel = silc_idlist_find_channel_by_id(server->local_list->channels,
644 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
645 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
649 /* Check whether the sender of this command is on the channel. */
650 sender = (SilcClientList *)sock->user_data;
651 if (!silc_server_client_on_channel(sender, channel)) {
652 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
653 SILC_STATUS_ERR_NOT_ON_CHANNEL);
657 /* Check whether the channel is invite-only channel. If yes then the
658 sender of this command must be at least channel operator. */
661 /* Check whether the requested client is already on the channel. */
662 /* XXX if we are normal server we don't know about global clients on
663 the channel thus we must request it (NAMES command), check from
664 local cache as well. */
666 /* Find the connection data for the destination. If it is local we will
667 send it directly otherwise we will send it to router for routing. */
668 dest = silc_idlist_find_client_by_id(server->local_list->clients, dest_id);
670 dest_sock = (SilcSocketConnection)dest->connection;
672 dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
674 /* Send notify to the client that is invited to the channel */
675 silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
676 "%s invites you to channel %s",
677 sender->nickname, channel->channel_name);
679 /* Send command reply */
680 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
684 silc_server_command_free(cmd);
687 /* Quits connection to client. This gets called if client won't
688 close the connection even when it has issued QUIT command. */
690 SILC_TASK_CALLBACK(silc_server_command_quit_cb)
692 SilcServer server = (SilcServer)context;
693 SilcSocketConnection sock = server->sockets[fd];
695 /* Free all client specific data, such as client entry and entires
696 on channels this client may be on. */
697 silc_server_free_sock_user_data(server, sock);
699 /* Close the connection on our side */
700 silc_server_close_connection(server, sock);
703 /* Quits SILC session. This is the normal way to disconnect client. */
705 SILC_SERVER_CMD_FUNC(quit)
707 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
708 SilcServer server = cmd->server;
709 SilcSocketConnection sock = cmd->sock;
711 SILC_LOG_DEBUG(("Start"));
713 /* We quit the connection with little timeout */
714 silc_task_register(server->timeout_queue, sock->sock,
715 silc_server_command_quit_cb, server,
716 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
718 silc_server_command_free(cmd);
721 SILC_SERVER_CMD_FUNC(kill)
725 SILC_SERVER_CMD_FUNC(info)
729 SILC_SERVER_CMD_FUNC(connect)
733 /* Server side of command PING. This just replies to the ping. */
735 SILC_SERVER_CMD_FUNC(ping)
737 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
738 SilcServer server = cmd->server;
741 unsigned char *id_string;
743 argc = silc_command_get_arg_num(cmd->payload);
745 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
746 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
750 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
751 SILC_STATUS_ERR_TOO_MANY_PARAMS);
756 id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
758 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
759 SILC_STATUS_ERR_NO_SERVER_ID);
762 id = silc_id_str2id(id_string, SILC_ID_SERVER);
764 if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
766 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
769 silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
770 SILC_STATUS_ERR_NO_SUCH_SERVER);
777 silc_server_command_free(cmd);
780 SILC_SERVER_CMD_FUNC(oper)
789 SilcChannelList *channel;
791 } JoinInternalContext;
793 SILC_TASK_CALLBACK(silc_server_command_join_notify)
795 JoinInternalContext *ctx = (JoinInternalContext *)context;
797 if (ctx->channel->key && ctx->channel->key_len) {
798 silc_server_send_notify_to_channel(ctx->server, ctx->channel,
799 "%s (%s@%s) has joined channel %s",
800 ctx->nickname, ctx->username,
801 ctx->hostname, ctx->channel_name);
804 silc_task_register(ctx->server->timeout_queue, fd,
805 silc_server_command_join_notify, context,
806 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
810 /* Assembles NAMES command and executes it. This is called when client
811 joins to a channel and we wan't to send NAMES command reply to the
814 void silc_server_command_send_names(SilcServer server,
815 SilcSocketConnection sock,
816 SilcChannelList *channel)
818 SilcServerCommandContext cmd;
820 unsigned char *id_string;
822 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
823 buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
824 id_string, SILC_ID_CHANNEL_LEN);
826 cmd = silc_calloc(1, sizeof(*cmd));
827 cmd->payload = silc_command_parse_payload(buffer);
828 cmd->server = server;
830 cmd->pending = FALSE;
832 silc_server_command_names((void *)cmd);
833 silc_free(id_string);
837 /* Server side of command JOIN. Joins client into requested channel. If
838 the channel does not exist it will be created. */
840 SILC_SERVER_CMD_FUNC(join)
842 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
843 SilcServer server = cmd->server;
844 SilcSocketConnection sock = cmd->sock;
845 SilcBuffer buffer = cmd->packet->buffer;
846 int argc, i, tmp_len;
847 char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
848 unsigned char *passphrase, mode[4];
849 SilcChannelList *channel;
850 SilcServerID *router_id;
851 SilcIDCache *id_cache;
852 SilcBuffer packet, sp_buf;
853 SilcClientList *client;
855 SILC_LOG_DEBUG(("Start"));
857 #define LCC(x) server->local_list->channel_cache[(x) - 32]
858 #define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
860 /* Check number of parameters */
861 argc = silc_command_get_arg_num(cmd->payload);
863 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
864 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
868 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
869 SILC_STATUS_ERR_TOO_MANY_PARAMS);
873 /* Get channel name */
874 tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
875 channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
876 memcpy(channel_name, tmp, tmp_len);
877 if (silc_server_command_bad_chars(tmp) == TRUE) {
878 silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
879 SILC_STATUS_ERR_BAD_CHANNEL);
880 silc_free(channel_name);
885 tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
887 passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
888 memcpy(passphrase, tmp, tmp_len);
891 /* Get cipher name */
892 cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
894 /* See if the channel exists */
895 if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]),
896 channel_name, &id_cache) == FALSE) {
897 /* Channel not found */
900 /* If we are standalone server we don't have a router, we just create
901 the channel by ourselves. */
902 if (server->standalone) {
903 router_id = server->id;
904 channel = silc_server_new_channel(server, router_id,
905 cipher, channel_name);
909 /* No channel ID found, the channel does not exist on our server.
910 We send JOIN command to our router which will handle the joining
911 procedure (either creates the channel if it doesn't exist or
912 joins the client to it) - if we are normal server. */
913 if (server->server_type == SILC_SERVER) {
915 /* Forward the original JOIN command to the router */
916 silc_buffer_push(buffer, buffer->data - buffer->head);
917 silc_server_packet_forward(server, (SilcSocketConnection)
918 server->id_entry->router->connection,
919 buffer->data, buffer->len, TRUE);
921 /* Add the command to be pending. It will be re-executed after
922 router has replied back to us. */
924 silc_server_command_pending(SILC_COMMAND_JOIN,
925 silc_server_command_join, context);
930 /* If we are router and the channel does not exist we will check our
931 global list for the channel. */
932 if (!id_cache && server->server_type == SILC_ROUTER) {
934 /* Notify all routers about the new channel in SILC network. */
935 if (!server->standalone) {
937 silc_server_send_new_id(server, server->id_entry->router->connection,
939 xxx, SILC_ID_CHANNEL, SILC_ID_CHANNEL_LEN);
945 channel = (SilcChannelList *)id_cache->context;
949 /* XXX must check whether the client already is on the channel */
951 /* Join the client to the channel */
952 i = channel->user_list_count;
953 channel->user_list = silc_realloc(channel->user_list,
954 sizeof(*channel->user_list) * (i + 1));
955 channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
957 /* If the JOIN request was forwarded to us we will make a bit slower
958 query to get the client pointer. Otherwise, we get the client pointer
960 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
961 client = (SilcClientList *)sock->user_data;
962 channel->user_list[i].client = client;
964 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
965 client = silc_idlist_find_client_by_id(server->local_list->clients, id);
966 channel->user_list[i].client = client;
969 channel->user_list_count++;
971 i = client->channel_count;
972 client->channel = silc_realloc(client->channel,
973 sizeof(*client->channel) * (i + 1));
974 client->channel[i] = channel;
975 client->channel_count++;
977 /* Notify router about new user on channel. If we are normal server
978 we send it to our router, if we are router we send it to our
980 if (!server->standalone) {
984 /* Send command reply to the client. Client receives the Channe ID,
985 channel mode and possibly other information in this reply packet. */
987 id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
988 sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
989 SILC_PUT32_MSB(channel->mode, mode);
993 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
994 sp_buf->data, sp_buf->len,
995 channel_name, strlen(channel_name),
996 id_string, SILC_ID_CHANNEL_LEN,
1000 silc_command_encode_payload_va(SILC_COMMAND_JOIN, 5,
1001 sp_buf->data, sp_buf->len,
1002 channel_name, strlen(channel_name),
1003 id_string, SILC_ID_CHANNEL_LEN,
1005 channel->topic, strlen(channel->topic));
1007 if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
1008 void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
1009 silc_server_packet_send_dest(cmd->server, cmd->sock,
1010 SILC_PACKET_COMMAND_REPLY, 0,
1011 id, cmd->packet->src_id_type,
1012 packet->data, packet->len, FALSE);
1015 silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
1016 packet->data, packet->len, FALSE);
1018 silc_buffer_free(packet);
1022 /* Send channel key to the client. Client cannot start transmitting
1023 to the channel until we have sent the key. */
1024 if (!cmd->pending) {
1025 tmp_len = strlen(channel->channel_key->cipher->name);
1027 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN,
1029 channel->channel_key->cipher->name,
1030 channel->key_len / 8, channel->key);
1032 silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
1033 packet->data, packet->len, FALSE);
1034 silc_buffer_free(packet);
1038 silc_free(id_string);
1040 /* Finally, send notify message to all clients on the channel about
1041 new user on the channel. */
1042 if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
1043 if (!cmd->pending) {
1044 silc_server_send_notify_to_channel(server, channel,
1045 "%s (%s@%s) has joined channel %s",
1046 client->nickname, client->username,
1047 sock->hostname ? sock->hostname :
1048 sock->ip, channel_name);
1050 /* This is pending command request. Send the notify after we have
1051 received the key for the channel from the router. */
1052 JoinInternalContext *ctx = silc_calloc(1, sizeof(*ctx));
1053 ctx->channel_name = channel_name;
1054 ctx->nickname = client->nickname;
1055 ctx->username = client->username;
1056 ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
1057 ctx->channel = channel;
1058 ctx->server = server;
1059 silc_task_register(server->timeout_queue, sock->sock,
1060 silc_server_command_join_notify, ctx,
1061 0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
1065 /* Send NAMES command reply to the joined channel so the user sees who
1066 is currently on the channel. */
1067 silc_server_command_send_names(server, sock, channel);
1070 silc_server_command_free(cmd);
1075 /* Server side of command MOTD. Sends servers current "message of the
1076 day" to the client. */
1078 SILC_SERVER_CMD_FUNC(motd)
1081 SILC_LOG_DEBUG(("Start"));
1085 SILC_SERVER_CMD_FUNC(umode)
1089 SILC_SERVER_CMD_FUNC(cmode)
1093 SILC_SERVER_CMD_FUNC(kick)
1097 SILC_SERVER_CMD_FUNC(restart)
1101 SILC_SERVER_CMD_FUNC(close)
1105 SILC_SERVER_CMD_FUNC(die)
1109 SILC_SERVER_CMD_FUNC(silcoper)
1113 /* Server side command of LEAVE. Removes client from a channel. */
1115 SILC_SERVER_CMD_FUNC(leave)
1117 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1118 SilcServer server = cmd->server;
1119 SilcSocketConnection sock = cmd->sock;
1120 SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
1122 SilcChannelList *channel;
1124 unsigned int i, argc, key_len;
1125 unsigned char *tmp, channel_key[32];
1127 SILC_LOG_DEBUG(("Start"));
1129 argc = silc_command_get_arg_num(cmd->payload);
1131 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1132 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1136 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1137 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1141 /* Get Channel ID */
1142 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1144 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1145 SILC_STATUS_ERR_NO_CHANNEL_ID);
1148 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1150 /* Get channel entry */
1151 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1153 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1154 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1158 /* Check whether this client is on the channel */
1159 if (!silc_server_client_on_channel(id_entry, channel)) {
1160 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1161 SILC_STATUS_ERR_NOT_ON_CHANNEL);
1165 /* Remove client from channel */
1166 i = silc_server_remove_from_one_channel(server, sock, channel, id_entry);
1167 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1170 /* If the channel does not exist anymore we won't send anything */
1174 /* Re-generate channel key */
1175 key_len = channel->key_len / 8;
1176 for (i = 0; i < key_len; i++)
1177 channel_key[i] = silc_rng_get_byte(server->rng);
1178 channel->channel_key->cipher->set_key(channel->channel_key->context,
1179 channel_key, key_len);
1180 memset(channel->key, 0, key_len);
1181 silc_free(channel->key);
1182 channel->key = silc_calloc(key_len, sizeof(*channel->key));
1183 memcpy(channel->key, channel_key, key_len);
1184 memset(channel_key, 0, sizeof(channel_key));
1186 /* Encode channel key payload to be distributed on the channel */
1188 silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, tmp,
1189 strlen(channel->channel_key->cipher->name),
1190 channel->channel_key->cipher->name,
1191 key_len, channel->key);
1193 /* If we are normal server then we will send it to our router. If we
1194 are router we will send it to all local servers that has clients on
1196 if (server->server_type == SILC_SERVER) {
1197 if (!server->standalone)
1198 silc_server_packet_send(server,
1199 cmd->server->id_entry->router->connection,
1200 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
1206 /* Send to locally connected clients on the channel */
1207 silc_server_packet_send_local_channel(server, channel,
1208 SILC_PACKET_CHANNEL_KEY, 0,
1209 packet->data, packet->len, FALSE);
1211 silc_buffer_free(packet);
1215 silc_server_command_free(cmd);
1218 /* Server side of command NAMES. Resolves clients and their names currently
1219 joined on the requested channel. The name list is sent back to the
1222 SILC_SERVER_CMD_FUNC(names)
1224 SilcServerCommandContext cmd = (SilcServerCommandContext)context;
1225 SilcServer server = cmd->server;
1226 SilcChannelList *channel;
1228 unsigned int i, len, len2, argc;
1230 char *name_list = NULL, *n;
1232 SILC_LOG_DEBUG(("Start"));
1234 argc = silc_command_get_arg_num(cmd->payload);
1236 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1237 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1241 silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
1242 SILC_STATUS_ERR_TOO_MANY_PARAMS);
1246 /* Get Channel ID */
1247 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
1249 silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
1250 SILC_STATUS_ERR_NO_CHANNEL_ID);
1253 id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
1255 /* Check whether the channel exists. If we are normal server and the
1256 channel does not exist we will send this same command to our router
1257 which will know if the channel exists. */
1258 channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
1260 if (server->server_type == SILC_SERVER && !server->standalone) {
1261 /* XXX Send names command */
1263 cmd->pending = TRUE;
1264 silc_server_command_pending(SILC_COMMAND_NAMES,
1265 silc_server_command_names, context);
1269 silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
1270 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
1274 /* Assemble the name list now */
1277 for (i = 0; i < channel->user_list_count; i++) {
1278 n = channel->user_list[i].client->nickname;
1282 name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
1283 memcpy(name_list + (len - len2), n, len2);
1286 if (i == channel->user_list_count - 1)
1288 memcpy(name_list + len, ",", 1);
1293 /* Send the reply */
1294 silc_server_command_send_status_msg(cmd, SILC_COMMAND_NAMES, SILC_STATUS_OK,
1295 name_list, strlen(name_list));
1297 silc_free(name_list);
1301 silc_server_command_free(cmd);