- TRUE, signoff, TRUE);
- else
- silc_server_remove_from_channels(server, NULL, client,
- FALSE, NULL, FALSE);
-
- /* We will not delete the client entry right away. We will take it
- into history (for WHOWAS command) for 5 minutes */
- i->server = server;
- i->client = client;
- silc_schedule_task_add(server->schedule, 0,
- silc_server_free_client_data_timeout,
- (void *)i, 300, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
- client->data.registered = FALSE;
- client->router = NULL;
- client->connection = NULL;
-
- /* Free the client entry and everything in it */
- server->stat.my_clients--;
- server->stat.clients--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients--;
-}
-
-/* Frees user_data pointer from socket connection object. This also sends
- appropriate notify packets to the network to inform about leaving
- entities. */
-
-void silc_server_free_sock_user_data(SilcServer server,
- SilcSocketConnection sock)
-{
- SILC_LOG_DEBUG(("Start"));
-
- switch(sock->type) {
- case SILC_SOCKET_TYPE_CLIENT:
- {
- SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
- silc_server_free_client_data(server, sock, user_data, TRUE, NULL);
- break;
- }
- case SILC_SOCKET_TYPE_SERVER:
- case SILC_SOCKET_TYPE_ROUTER:
- {
- SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
-
- /* Free all client entries that this server owns as they will
- become invalid now as well. */
- if (user_data->id)
- silc_server_remove_clients_by_server(server, user_data, TRUE);
-
- /* If this was our primary router connection then we're lost to
- the outside world. */
- if (server->router == user_data) {
- server->id_entry->router = NULL;
- server->router = NULL;
- server->standalone = TRUE;
- }
-
- /* Free the server entry */
- silc_idlist_del_data(user_data);
- silc_idlist_del_server(server->local_list, user_data);
- server->stat.my_servers--;
- server->stat.servers--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_servers--;
- break;
- }
- default:
- {
- SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
-
- silc_idlist_del_data(user_data);
- silc_free(user_data);
- break;
- }
- }
-
- /* If any protocol is active cancel its execution */
- if (sock->protocol) {
- silc_protocol_cancel(sock->protocol, server->schedule);
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
- silc_protocol_execute_final(sock->protocol, server->schedule);
- sock->protocol = NULL;
- }
-
- sock->user_data = NULL;
-}
-
-/* Removes the client from channels and possibly removes the channels
- as well. After removing those channels that exist, their channel
- keys are regnerated. This is called only by the function
- silc_server_remove_clients_by_server. */
-
-static void silc_server_remove_clients_channels(SilcServer server,
- SilcSocketConnection sock,
- SilcClientEntry client,
- SilcHashTable channels)
-{
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- SilcHashTableList htl;
- SilcBuffer clidp;
-
- SILC_LOG_DEBUG(("Start"));
-
- if (!client || !client->id)
- return;
-
- clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Remove the client from all channels. The client is removed from
- the channels' user list. */
- silc_hash_table_list(client->channels, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- channel = chl->channel;
-
- /* Remove channel from client's channel list */
- silc_hash_table_del(client->channels, channel);
-
- /* Remove channel if there is no users anymore */
- if (server->server_type == SILC_ROUTER &&
- silc_hash_table_count(channel->user_list) < 2) {
-
- if (silc_hash_table_find(channels, channel, NULL, NULL))
- silc_hash_table_del(channels, channel);
-
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
- continue;
- }
-
- /* Remove client from channel's client list */
- silc_hash_table_del(channel->user_list, chl->client);
- silc_free(chl);
- server->stat.my_chanclients--;
-
- /* If there is no global users on the channel anymore mark the channel
- as local channel. Do not check if the removed client is local client. */
- if (server->server_type == SILC_SERVER && channel->global_users &&
- chl->client->router && !silc_server_channel_has_global(channel))
- channel->global_users = FALSE;
-
- /* If there is not at least one local user on the channel then we don't
- need the channel entry anymore, we can remove it safely. */
- if (server->server_type == SILC_SERVER &&
- !silc_server_channel_has_local(channel)) {
-
- if (silc_hash_table_find(channels, channel, NULL, NULL))
- silc_hash_table_del(channels, channel);
-
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (channel->founder_key) {
- /* The founder auth data exists, do not remove the channel entry */
- SilcChannelClientEntry chl2;
- SilcHashTableList htl2;
-
- channel->id = NULL;
-
- silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
- silc_hash_table_del(chl2->client->channels, channel);
- silc_hash_table_del(channel->user_list, chl2->client);
- silc_free(chl2);
- }
- continue;
- }
-
- /* Remove the channel entry */
- if (!silc_idlist_del_channel(server->local_list, channel))
- silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
- continue;
- }
-
- /* Add the channel to the the channels list to regenerate the
- channel key */
- if (!silc_hash_table_find(channels, channel, NULL, NULL))
- silc_hash_table_add(channels, channel, channel);
- }