SilcServerEntry server_entry;
SilcChannelClientEntry chl;
SilcIDCacheEntry cache;
+ SilcHashTableList htl;
uint32 mode;
unsigned char *tmp;
uint32 tmp_len;
goto out;
client =
- silc_idlist_add_client(server->global_list, NULL, 0, NULL, NULL,
+ silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
chl = silc_calloc(1, sizeof(*chl));
chl->client = client;
chl->channel = channel;
- silc_list_add(channel->user_list, chl);
- silc_list_add(client->channels, chl);
+ silc_hash_table_add(channel->user_list, client, chl);
+ silc_hash_table_add(client->channels, channel, chl);
silc_free(client_id);
break;
silc_free(client_id);
/* Get entry to the channel user list */
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ SilcChannelClientEntry chl2 = NULL;
+
+ /* If the mode is channel founder and we already find a client
+ to have that mode on the channel we will enforce the sender
+ to change the channel founder mode away. There can be only one
+ channel founder on the channel. */
+ if (server->server_type == SILC_ROUTER &&
+ mode & SILC_CHANNEL_UMODE_CHANFO &&
+ chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ silc_server_send_notify_cumode(server, sock, FALSE, channel,
+ (mode & (~SILC_CHANNEL_UMODE_CHANFO)),
+ server->id, SILC_ID_SERVER,
+ client->id);
+ silc_free(channel_id);
+
+ /* Change the mode back if we changed it */
+ if (chl2)
+ chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ goto out;
+ }
+
if (chl->client == client) {
/* Change the mode */
chl->mode = mode;
- break;
+ if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+ break;
+
+ chl2 = chl;
}
+ }
/* Send the same notify to the channel */
silc_server_packet_send_to_channel(server, sock, channel, packet->type,
}
if (channel_id2) {
- SilcBuffer users = NULL;
+ SilcBuffer users = NULL, users_modes = NULL;
/* Re-announce our clients on the channel as the ID has changed now */
- silc_server_announce_get_channel_users(server, channel, &users);
+ silc_server_announce_get_channel_users(server, channel, &users,
+ &users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users_modes->data, users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
}
silc_free(channel_id);
SilcBuffer buffer;
uint16 len;
- SILC_LOG_DEBUG(("Processing New Notify List"));
+ SILC_LOG_DEBUG(("Processing Notify List"));
if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
packet->src_id_type != SILC_ID_SERVER)
if (packet->dst_id_type == SILC_ID_SERVER) {
/* For now this must be for us */
- if (SILC_ID_SERVER_COMPARE(packet->dst_id, server->id_string)) {
+ if (memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
return;
}
SilcPacketContext *packet)
{
SilcChannelEntry channel = NULL;
- SilcChannelClientEntry chl;
SilcChannelID *id = NULL;
void *sender = NULL;
void *sender_entry = NULL;
}
}
- /* See that this client is on the channel. If the message is coming
- from router we won't do the check as the message is from client that
- we don't know about. Also, if the original sender is not client
- (as it can be server as well) we don't do the check. */
+ /* See that this client is on the channel. If the original sender is
+ not client (as it can be server as well) we don't do the check. */
sender = silc_id_str2id(packet->src_id, packet->src_id_len,
packet->src_id_type);
if (!sender)
goto out;
if (packet->src_id_type == SILC_ID_CLIENT) {
- silc_list_start(channel->user_list);
- while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) {
- sender_entry = chl->client;
- break;
- }
- }
- if (chl == SILC_LIST_END) {
+ sender_entry = silc_idlist_find_client_by_id(server->local_list,
+ sender, NULL);
+ if (!sender_entry)
+ sender_entry = silc_idlist_find_client_by_id(server->global_list,
+ sender, NULL);
+ if (!sender_entry || !silc_server_client_on_channel(sender_entry,
+ channel)) {
SILC_LOG_DEBUG(("Client not on channel"));
goto out;
}
{
SilcBuffer buffer = packet->buffer;
SilcClientEntry client;
- SilcIDCacheEntry cache;
SilcClientID *client_id;
SilcBuffer reply;
SilcIDListData idata;
char *username = NULL, *realname = NULL, *id_string;
+ uint32 id_len;
int ret;
SILC_LOG_DEBUG(("Creating new client"));
client = (SilcClientEntry)sock->user_data;
idata = (SilcIDListData)client;
- /* Fetch the old client cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->clients,
- sock->user_data, &cache)) {
+ /* Remove the old cache entry */
+ if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Unknown client");
client->username = username;
client->userinfo = realname ? realname : strdup(" ");
client->id = client_id;
+ id_len = silc_id_get_len(client_id, SILC_ID_CLIENT);
- /* Update the cache entry */
- cache->id = (void *)client_id;
- cache->type = SILC_ID_CLIENT;
- cache->data = username;
- cache->data_len = strlen(username);
- silc_idcache_sort_by_data(server->local_list->clients);
+ /* Add the client again to the ID cache */
+ silc_idcache_add(server->local_list->clients, client->nickname,
+ client_id, client, FALSE);
/* Notify our router about new client on the SILC network */
if (!server->standalone)
silc_server_send_new_id(server, (SilcSocketConnection)
server->router->connection,
server->server_type == SILC_ROUTER ? TRUE : FALSE,
- client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+ client->id, SILC_ID_CLIENT, id_len);
/* Send the new client ID to the client. */
id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
- reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
+ reply = silc_buffer_alloc(2 + 2 + id_len);
silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
silc_buffer_format(reply,
SILC_STR_UI_SHORT(SILC_ID_CLIENT),
- SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_SHORT(id_len),
+ SILC_STR_UI_XNSTRING(id_string, id_len),
SILC_STR_END);
silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0,
reply->data, reply->len, FALSE);
{
SilcBuffer buffer = packet->buffer;
SilcServerEntry new_server;
- SilcIDCacheEntry cache;
SilcServerID *server_id;
SilcIDListData idata;
unsigned char *server_name, *id_string;
new_server = (SilcServerEntry)sock->user_data;
idata = (SilcIDListData)new_server;
- /* Fetch the old server cache entry so that we can update it. */
- if (!silc_idcache_find_by_context(server->local_list->servers,
- sock->user_data, &cache)) {
- SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
- return NULL;
- }
+ /* Remove the old cache entry */
+ silc_idcache_del_by_context(server->local_list->servers, new_server);
/* Parse the incoming packet */
ret = silc_buffer_unformat(buffer,
}
silc_free(id_string);
- /* Update client entry */
+ /* Update server entry */
idata->registered = TRUE;
new_server->server_name = server_name;
new_server->id = server_id;
- /* Update the cache entry */
- cache->id = (void *)server_id;
- cache->type = SILC_ID_SERVER;
- cache->data = server_name;
- cache->data_len = strlen(server_name);
- silc_idcache_sort_by_data(server->local_list->servers);
+ /* Add again the entry to the ID cache. */
+ silc_idcache_add(server->local_list->servers, server_name, server_id,
+ server, FALSE);
/* Distribute the information about new server in the SILC network
to our router. If we are normal server we won't send anything
server->router->connection != sock)
silc_server_send_new_id(server, server->router->connection,
TRUE, new_server->id, SILC_ID_SERVER,
- SILC_ID_SERVER_LEN);
+ silc_id_get_len(server_id, SILC_ID_SERVER));
if (server->server_type == SILC_ROUTER)
server->stat.cell_servers++;
SilcSocketConnection router_sock;
SilcIDPayload idp;
SilcIdType id_type;
- unsigned char *hash = NULL;
void *id;
SILC_LOG_DEBUG(("Processing new ID"));
/* As a router we keep information of all global information in our
global list. Cell wide information however is kept in the local
- list. The client is put to global list and we will take the hash
- value of the Client ID and save it to the ID Cache system for fast
- searching in the future. */
- hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
- sizeof(unsigned char));
- memcpy(hash, ((SilcClientID *)id)->hash,
- sizeof(((SilcClientID *)id)->hash));
- entry = silc_idlist_add_client(id_list, hash,
- sizeof(((SilcClientID *)id)->hash),
- NULL, NULL, id, router, NULL);
+ list. */
+ entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+ id, router, NULL);
entry->nickname = NULL;
entry->data.registered = TRUE;
case SILC_ID_SERVER:
/* If the ID is mine, ignore it. */
- if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+ if (SILC_ID_SERVER_COMPARE(id, server->id)) {
SILC_LOG_DEBUG(("Ignoring my own ID as new ID"));
break;
}
/* The channel exist by that name, check whether the ID's match.
If they don't then we'll force the server to use the ID we have.
We also create a new key for the channel. */
- SilcBuffer users = NULL;
+ SilcBuffer users = NULL, users_modes = NULL;
if (!channel->id)
channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
- if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
+ if (!SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
/* They don't match, send CHANNEL_CHANGE notify to the server to
force the ID change. */
SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
silc_server_send_notify_channel_change(server, sock, FALSE,
- channel_id,
- channel->id,
- SILC_ID_CHANNEL_LEN);
+ channel_id, channel->id);
}
/* If the mode is different from what we have then enforce the
SILC_LOG_DEBUG(("Forcing the server to change channel mode"));
silc_server_send_notify_cmode(server, sock, FALSE, channel,
channel->mode, server->id,
- SILC_ID_SERVER, SILC_ID_SERVER_LEN,
+ SILC_ID_SERVER,
channel->cipher, channel->hmac_name);
}
/* Since the channel is coming from server and we also know about it
then send the JOIN notify to the server so that it see's our
users on the channel "joining" the channel. */
- silc_server_announce_get_channel_users(server, channel, &users);
+ silc_server_announce_get_channel_users(server, channel, &users,
+ &users_modes);
if (users) {
silc_buffer_push(users, users->data - users->head);
silc_server_packet_send(server, sock,
users->data, users->len, FALSE);
silc_buffer_free(users);
}
+ if (users_modes) {
+ silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+ silc_server_packet_send(server, sock,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ users_modes->data, users_modes->len, FALSE);
+ silc_buffer_free(users_modes);
+ }
}
}