- /* Check for same nickname */
- if (!strcmp(client->nickname, nick)) {
- nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
- goto send_reply;
- }
-
- /* Create new Client ID */
- while (!silc_id_create_client_id(cmd->server, cmd->server->id,
- cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id)) {
- nickfail++;
- snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
- }
-
- /* Send notify about nickname change to our router. We send the new
- ID and ask to replace it with the old one. If we are router the
- packet is broadcasted. Send NICK_CHANGE notify. */
- if (!server->standalone)
- silc_server_send_notify_nick_change(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, client->id,
- new_id);
-
- oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Remove old cache entry */
- silc_idcache_del_by_context(server->local_list->clients, client);
-
- /* Free old ID */
- silc_free(client->id);
-
- /* Save the nickname as this client is our local client */
- silc_free(client->nickname);
-
- client->nickname = strdup(nick);
- client->id = new_id;
-
- /* Update client cache */
- silc_idcache_add(server->local_list->clients, client->nickname,
- client->id, (void *)client, 0, NULL);
-
- nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Send NICK_CHANGE notify to the client's channels */
- silc_server_send_notify_on_channels(server, NULL, client,
- SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
- oidp->data, oidp->len,
- nidp->data, nidp->len);
-
- send_reply:
- /* Send the new Client ID as reply command back to client */
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
- SILC_STATUS_OK, ident, 1,
- 2, nidp->data, nidp->len);
- silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(nidp);
- if (oidp)
- silc_buffer_free(oidp);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Sends the LIST command reply */
-
-static void
-silc_server_command_list_send_reply(SilcServerCommandContext cmd,
- SilcChannelEntry *lch,
- uint32 lch_count,
- SilcChannelEntry *gch,
- uint32 gch_count)
-{
- int i, k;
- SilcBuffer packet, idp;
- SilcChannelEntry entry;
- SilcCommandStatus status;
- uint16 ident = silc_command_get_ident(cmd->payload);
- char *topic;
- unsigned char usercount[4];
- uint32 users;
- int valid_lcount = 0, valid_rcount = 0;
-
- for (i = 0; i < lch_count; i++) {
- if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
- lch[i] = NULL;
- else
- valid_lcount++;
- }
- for (i = 0; i < gch_count; i++) {
- if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
- gch[i] = NULL;
- else
- valid_rcount++;
- }
-
- status = SILC_STATUS_OK;
- if ((lch_count + gch_count) > 1)
- status = SILC_STATUS_LIST_START;
-
- /* Local list */
- for (i = 0, k = 0; i < lch_count; i++) {
- entry = lch[i];
- if (!entry)
- continue;
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (valid_lcount > 1 && k == valid_lcount - 1 && !valid_rcount)
- status = SILC_STATUS_LIST_END;
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-
- if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
- topic = "*private*";
- memset(usercount, 0, sizeof(usercount));
- } else {
- topic = entry->topic;
- users = silc_hash_table_count(entry->user_list);
- SILC_PUT32_MSB(users, usercount);
- }
-
- /* Send the reply */
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, topic ? strlen(topic) : 0,
- 5, usercount, 4);
- silc_server_packet_send(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0, packet->data,
- packet->len, FALSE);
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- k++;
- }
-
- /* Global list */
- for (i = 0, k = 0; i < gch_count; i++) {
- entry = gch[i];
- if (!entry)
- continue;
-
- if (k >= 1)
- status = SILC_STATUS_LIST_ITEM;
- if (valid_rcount > 1 && k == valid_rcount - 1)
- status = SILC_STATUS_LIST_END;
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-
- if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
- topic = "*private*";
- memset(usercount, 0, sizeof(usercount));
- } else {
- topic = entry->topic;
- users = entry->user_count;
- SILC_PUT32_MSB(users, usercount);
- }
-
- /* Send the reply */
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
- status, ident, 4,
- 2, idp->data, idp->len,
- 3, entry->channel_name,
- strlen(entry->channel_name),
- 4, topic, topic ? strlen(topic) : 0,
- 5, usercount, 4);
- silc_server_packet_send(cmd->server, cmd->sock,
- SILC_PACKET_COMMAND_REPLY, 0, packet->data,
- packet->len, FALSE);
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- k++;
- }
-}
-
-/* Server side of LIST command. This lists the channel of the requested
- server. Secret channels are not listed. */
-
-SILC_SERVER_CMD_FUNC(list)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcChannelID *channel_id = NULL;
- unsigned char *tmp;
- uint32 tmp_len;
- SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
- uint32 lch_count = 0, gch_count = 0;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
-
- /* If we are normal server, send the command to router, since we
- want to know all channels in the network. */
- if (!cmd->pending && server->server_type == SILC_SERVER &&
- !server->standalone) {
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
- silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_LIST,
- silc_command_get_ident(cmd->payload),
- silc_server_command_list,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
- goto out;
- }
-
- /* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (tmp) {
- channel_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!channel_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
- }
- }
-
- /* Get the channels from local list */
- lchannels = silc_idlist_get_channels(server->local_list, channel_id,
- &lch_count);
-
- /* Get the channels from global list */
- gchannels = silc_idlist_get_channels(server->global_list, channel_id,
- &gch_count);
-
- /* Send the reply */
- silc_server_command_list_send_reply(cmd, lchannels, lch_count,
- gchannels, gch_count);
-
- silc_free(lchannels);
- silc_free(gchannels);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side of TOPIC command. Sets topic for channel and/or returns
- current topic to client. */
-
-SILC_SERVER_CMD_FUNC(topic)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SilcChannelID *channel_id;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- SilcBuffer packet, idp;
- unsigned char *tmp;
- uint32 argc, tmp_len;
- uint16 ident = silc_command_get_ident(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_TOPIC, cmd, 1, 2);
-
- argc = silc_argument_get_arg_num(cmd->args);
-
- /* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
- }
- channel_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!channel_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
- }
-
- /* Check whether the channel exists */
- channel = silc_idlist_find_channel_by_id(server->local_list,
- channel_id, NULL);
- if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->global_list,
- channel_id, NULL);
- if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
- }
- }
-
- if (argc > 1) {
- /* Get the topic */
- tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (strlen(tmp) > 256) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* See whether the client is on channel and has rights to change topic */
- if (!silc_hash_table_find(channel->user_list, client, NULL,
- (void *)&chl)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
- if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
- goto out;
- }
- }
-
- /* Set the topic for channel */
- silc_free(channel->topic);
- channel->topic = strdup(tmp);
-
- /* Send TOPIC_SET notify type to the network */
- if (!server->standalone)
- silc_server_send_notify_topic_set(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
- client->id, SILC_ID_CLIENT,
- channel->topic);
-
- idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Send notify about topic change to all clients on the channel */
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_TOPIC_SET, 2,
- idp->data, idp->len,
- channel->topic, strlen(channel->topic));
- silc_buffer_free(idp);
- }
-
- /* Send the topic to client as reply packet */
- idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
- SILC_STATUS_OK, ident, 2,
- 2, idp->data, idp->len,
- 3, channel->topic,
- channel->topic ?
- strlen(channel->topic) : 0);
- silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
- 0, packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
- silc_free(channel_id);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side of INVITE command. Invites some client to join some channel.
- This command is also used to manage the invite list of the channel. */
-
-SILC_SERVER_CMD_FUNC(invite)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock, dest_sock;
- SilcChannelClientEntry chl;
- SilcClientEntry sender, dest;
- SilcClientID *dest_id = NULL;
- SilcChannelEntry channel;
- SilcChannelID *channel_id = NULL;
- SilcIDListData idata;
- SilcBuffer idp, idp2, packet;
- unsigned char *tmp, *add, *del;
- uint32 len;
- uint16 ident = silc_command_get_ident(cmd->payload);
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
-
- /* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
- }
- channel_id = silc_id_payload_parse_id(tmp, len);
- if (!channel_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CHANNEL_ID);
- goto out;
- }
-
- /* Get the channel entry */
- channel = silc_idlist_find_channel_by_id(server->local_list,
- channel_id, NULL);
- if (!channel) {
- channel = silc_idlist_find_channel_by_id(server->global_list,
- channel_id, NULL);
- if (!channel) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CHANNEL);
- goto out;
- }
- }
-
- /* Check whether the sender of this command is on the channel. */
- sender = (SilcClientEntry)sock->user_data;
- if (!silc_server_client_on_channel(sender, channel)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NOT_ON_CHANNEL);
- goto out;
- }
-
- /* Check whether the channel is invite-only channel. If yes then the
- sender of this command must be at least channel operator. */
- if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
- silc_hash_table_find(channel->user_list, sender, NULL, (void *)&chl);
- if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
- goto out;
- }
- }
-
- /* Get destination client ID */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
- if (tmp) {
- char invite[512];
- bool resolve;
-
- dest_id = silc_id_payload_parse_id(tmp, len);
- if (!dest_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_CLIENT_ID);
- goto out;
- }
-
- /* Get the client entry */
- dest = silc_server_get_client_resolve(server, dest_id, &resolve);
- if (!dest) {
- if (server->server_type != SILC_SERVER || !resolve) {
- silc_server_command_send_status_reply(
- cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
-
- /* The client info is being resolved. Reprocess this packet after
- receiving the reply to the query. */
- silc_server_command_pending(server, SILC_COMMAND_WHOIS,
- server->cmd_ident,
- silc_server_command_invite,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_free(channel_id);
- silc_free(dest_id);
- goto out;
- }
-
- /* Check whether the requested client is already on the channel. */
- if (silc_server_client_on_channel(dest, channel)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_USER_ON_CHANNEL);
- goto out;
- }
-
- /* Get route to the client */
- dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
- if (!dest_sock) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
-
- memset(invite, 0, sizeof(invite));
- strncat(invite, dest->nickname, strlen(dest->nickname));
- strncat(invite, "!", 1);
- strncat(invite, dest->username, strlen(dest->username));
- if (!strchr(dest->username, '@')) {
- strncat(invite, "@", 1);
- strncat(invite, cmd->sock->hostname, strlen(cmd->sock->hostname));
- }
-
- len = strlen(invite);
- if (!channel->invite_list)
- channel->invite_list = silc_calloc(len + 2,
- sizeof(*channel->invite_list));
- else
- channel->invite_list = silc_realloc(channel->invite_list,
- sizeof(*channel->invite_list) *
- (len +
- strlen(channel->invite_list) + 2));
- strncat(channel->invite_list, invite, len);
- strncat(channel->invite_list, ",", 1);
-
- /* Send notify to the client that is invited to the channel */
- idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
- idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
- silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
- SILC_ID_CLIENT,
- SILC_NOTIFY_TYPE_INVITE, 3,
- idp->data, idp->len,
- channel->channel_name,
- strlen(channel->channel_name),
- idp2->data, idp2->len);
- silc_buffer_free(idp);
- silc_buffer_free(idp2);
- }
-
- /* Add the client to the invite list of the channel */
- add = silc_argument_get_arg_type(cmd->args, 3, &len);
- if (add) {
- if (!channel->invite_list)
- channel->invite_list = silc_calloc(len + 2,
- sizeof(*channel->invite_list));
- else
- channel->invite_list = silc_realloc(channel->invite_list,
- sizeof(*channel->invite_list) *
- (len +
- strlen(channel->invite_list) + 2));
- if (add[len - 1] == ',')
- add[len - 1] = '\0';
-
- strncat(channel->invite_list, add, len);
- strncat(channel->invite_list, ",", 1);
- }
-
- /* Get the invite to be removed and remove it from the list */
- del = silc_argument_get_arg_type(cmd->args, 4, &len);
- if (del && channel->invite_list) {
- char *start, *end, *n;
-
- if (!strncmp(channel->invite_list, del,
- strlen(channel->invite_list) - 1)) {
- silc_free(channel->invite_list);
- channel->invite_list = NULL;
- } else {
- start = strstr(channel->invite_list, del);
- if (start && strlen(start) >= len) {
- end = start + len;
- n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
- strncat(n, channel->invite_list, start - channel->invite_list);
- strncat(n, end + 1, ((channel->invite_list +
- strlen(channel->invite_list)) - end) - 1);
- silc_free(channel->invite_list);
- channel->invite_list = n;
- }
- }
- }
-
- /* Send notify to the primary router */
- if (!server->standalone)
- silc_server_send_notify_invite(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
- sender->id, add, del);
-
- /* Send command reply */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
-
- if (add || del)
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
- SILC_STATUS_OK, ident, 2,
- 2, tmp, len,
- 3, channel->invite_list,
- channel->invite_list ?
- strlen(channel->invite_list) : 0);
- else
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
- SILC_STATUS_OK, ident, 1,
- 2, tmp, len);
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
- silc_buffer_free(packet);
-
- out:
- silc_free(dest_id);
- silc_free(channel_id);
- silc_server_command_free(cmd);
-}
-
-typedef struct {
- SilcServer server;
- SilcSocketConnection sock;
- char *signoff;
-} *QuitInternal;
-
-/* Quits connection to client. This gets called if client won't
- close the connection even when it has issued QUIT command. */
-
-SILC_TASK_CALLBACK(silc_server_command_quit_cb)
-{
- QuitInternal q = (QuitInternal)context;
-
- /* Free all client specific data, such as client entry and entires
- on channels this client may be on. */
- silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
- TRUE, q->signoff);
- q->sock->user_data = NULL;
-
- /* Close the connection on our side */
- silc_server_close_connection(q->server, q->sock);
-
- silc_free(q->signoff);
- silc_free(q);
-}
-
-/* Quits SILC session. This is the normal way to disconnect client. */
-
-SILC_SERVER_CMD_FUNC(quit)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock;
- QuitInternal q;
- unsigned char *tmp = NULL;
- uint32 len = 0;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_QUIT, cmd, 0, 1);
-
- if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- /* Get destination ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (len > 128)
- tmp = NULL;
-
- q = silc_calloc(1, sizeof(*q));
- q->server = server;
- q->sock = sock;
- q->signoff = tmp ? strdup(tmp) : NULL;
-
- /* We quit the connection with little timeout */
- silc_schedule_task_add(server->schedule, sock->sock,
- silc_server_command_quit_cb, (void *)q,
- 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side of command KILL. This command is used by router operator
- to remove an client from the SILC Network temporarily. */
-
-SILC_SERVER_CMD_FUNC(kill)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SilcClientEntry remote_client;
- SilcClientID *client_id;
- unsigned char *tmp, *comment;
- uint32 tmp_len, tmp_len2;
- bool local;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
-
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- /* KILL command works only on router */
- if (server->server_type != SILC_ROUTER) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_ROUTER_PRIV);
- goto out;
- }
-
- /* Check whether client has the permissions. */
- if (!(client->mode & SILC_UMODE_ROUTER_OPERATOR)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_ROUTER_PRIV);
- goto out;
- }
-
- /* Get the client ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
- client_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!client_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
-
- /* Get the client entry */
- remote_client = silc_idlist_find_client_by_id(server->local_list,
- client_id, TRUE, NULL);
- local = TRUE;
- if (!remote_client) {
- remote_client = silc_idlist_find_client_by_id(server->global_list,
- client_id, TRUE, NULL);
- local = FALSE;
- if (!remote_client) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
- goto out;
- }
- }
-
- /* Get comment */
- comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
- if (tmp_len2 > 128)
- comment = NULL;
-
- /* Send reply to the sender */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
- SILC_STATUS_OK);
-
- /* Send the KILL notify packets. First send it to the channel, then
- to our primary router and then directly to the client who is being
- killed right now. */
-
- /* Send KILLED notify to the channels. It is not sent to the client
- as it will be sent differently destined directly to the client and not
- to the channel. */
- silc_server_send_notify_on_channels(server, remote_client,
- remote_client, SILC_NOTIFY_TYPE_KILLED,
- comment ? 2 : 1,
- tmp, tmp_len,
- comment, comment ? tmp_len2 : 0);
-
- /* Send KILLED notify to primary route */
- if (!server->standalone)
- silc_server_send_notify_killed(server, server->router->connection, TRUE,
- remote_client->id, comment);
-
- /* Send KILLED notify to the client directly */
- silc_server_send_notify_killed(server, remote_client->connection ?
- remote_client->connection :
- remote_client->router->connection, FALSE,
- remote_client->id, comment);
-
- /* Remove the client from all channels. This generates new keys to the
- channels as well. */
- silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
- NULL, TRUE);
-
- /* Remove the client entry, If it is locally connected then we will also
- disconnect the client here */
- if (remote_client->connection) {
- /* Remove locally conneted client */
- SilcSocketConnection sock = remote_client->connection;
- silc_server_free_client_data(server, sock, remote_client, FALSE, NULL);
- silc_server_close_connection(server, sock);
- } else {
- /* Update statistics */
- if (remote_client->connection)
- server->stat.my_clients--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients--;
- SILC_OPER_STATS_UPDATE(remote_client, server, SILC_UMODE_SERVER_OPERATOR);
- SILC_OPER_STATS_UPDATE(remote_client, router, SILC_UMODE_ROUTER_OPERATOR);
-
- /* Remove remote client */
- silc_idlist_del_client(local ? server->local_list :
- server->global_list, remote_client);
- }
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side of command INFO. This sends information about us to
- the client. If client requested specific server we will send the
- command to that server. */
-
-SILC_SERVER_CMD_FUNC(info)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcBuffer packet, idp;
- unsigned char *tmp;
- uint32 tmp_len;
- char *dest_server, *server_info = NULL, *server_name;
- uint16 ident = silc_command_get_ident(cmd->payload);
- SilcServerEntry entry = NULL;
- SilcServerID *server_id = NULL;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 0, 2);
-
- /* Get server name */
- dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
-
- /* Get Server ID */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp) {
- server_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!server_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_NO_SERVER_ID);
- goto out;
- }
- }
-
- if (server_id) {
- /* Check whether we have this server cached */
- entry = silc_idlist_find_server_by_id(server->local_list,
- server_id, TRUE, NULL);
- if (!entry) {
- entry = silc_idlist_find_server_by_id(server->global_list,
- server_id, TRUE, NULL);
- if (!entry && server->server_type != SILC_SERVER) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- goto out;
- }
- }
- }
-
- /* Some buggy servers has sent request to router about themselves. */
- if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
- goto out;
-
- if ((!dest_server && !server_id && !entry) || (entry &&
- entry == server->id_entry) ||
- (dest_server && !cmd->pending &&
- !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
- /* Send our reply */
- char info_string[256];
-
- memset(info_string, 0, sizeof(info_string));
- snprintf(info_string, sizeof(info_string),
- "location: %s server: %s admin: %s <%s>",
- server->config->server_info->location,
- server->config->server_info->server_type,
- server->config->server_info->admin,
- server->config->server_info->email);
-
- server_info = info_string;
- entry = server->id_entry;
- } else {
- /* Check whether we have this server cached */
- if (!entry && dest_server) {
- entry = silc_idlist_find_server_by_name(server->global_list,
- dest_server, TRUE, NULL);
- if (!entry) {
- entry = silc_idlist_find_server_by_name(server->local_list,
- dest_server, TRUE, NULL);
- }
- }
-
- if (!cmd->pending &&
- server->server_type != SILC_SERVER && entry && !entry->server_info) {
- /* Send to the server */
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- silc_server_packet_send(server, entry->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_INFO,
- silc_command_get_ident(cmd->payload),
- silc_server_command_info,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
- goto out;
- }
-
- if (!entry && !cmd->pending && !server->standalone) {
- /* Send to the primary router */
- SilcBuffer tmpbuf;
- uint16 old_ident;
-
- old_ident = silc_command_get_ident(cmd->payload);
- silc_command_set_ident(cmd->payload, ++server->cmd_ident);
- tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-
- silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_COMMAND, cmd->packet->flags,
- tmpbuf->data, tmpbuf->len, TRUE);
-
- /* Reprocess this packet after received reply from router */
- silc_server_command_pending(server, SILC_COMMAND_INFO,
- silc_command_get_ident(cmd->payload),
- silc_server_command_info,
- silc_server_command_dup(cmd));
- cmd->pending = TRUE;
- silc_command_set_ident(cmd->payload, old_ident);
- silc_buffer_free(tmpbuf);
- goto out;
- }
- }
-
- silc_free(server_id);
-
- if (!entry) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
- SILC_STATUS_ERR_NO_SUCH_SERVER);
- goto out;
- }
-
- idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
- if (!server_info)
- server_info = entry->server_info;
- server_name = entry->server_name;
-
- /* Send the reply */
- packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, ident, 3,
- 2, idp->data, idp->len,
- 3, server_name,
- strlen(server_name),
- 4, server_info,
- server_info ?
- strlen(server_info) : 0);
- silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
- packet->data, packet->len, FALSE);
-
- silc_buffer_free(packet);
- silc_buffer_free(idp);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side of command PING. This just replies to the ping. */
-
-SILC_SERVER_CMD_FUNC(ping)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcServerID *id;
- uint32 len;
- unsigned char *tmp;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INFO, cmd, 1, 2);