out:
silc_buffer_clear(buffer);
+ if (packet->src_id)
+ silc_free(packet->src_id);
+ if (packet->dst_id)
+ silc_free(packet->dst_id);
silc_free(packet);
silc_free(parse_ctx);
}
* protocol and it will call the final callback.
*/
if (sock->protocol) {
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
sock->protocol->execute(client->timeout_queue, 0,
sock->protocol, sock->sock, 0, 0);
+
+ /* XXX We have only two protocols currently thus we know what this
+ failure indication is. */
+ if (buffer->len >= 4) {
+ unsigned int failure;
+
+ SILC_GET32_MSB(failure, buffer->data);
+
+ /* Notify application */
+ client->ops->failure(client, sock->user_data, sock->protocol,
+ (void *)failure);
+ }
}
break;
case SILC_PACKET_REJECT:
/*
* Received notify message
*/
- silc_client_notify_by_server(client, sock, buffer);
+ silc_client_notify_by_server(client, sock, packet);
break;
case SILC_PACKET_ERROR:
* user changes nickname but in that case the new ID is received
* as command reply and not as this packet type.
*/
- unsigned char *id_string;
- unsigned short id_type;
-
- silc_buffer_unformat(buffer,
- SILC_STR_UI_SHORT(&id_type),
- SILC_STR_UI16_STRING_ALLOC(&id_string),
- SILC_STR_END);
-
- if ((SilcIdType)id_type != SILC_ID_CLIENT)
+ SilcIDPayload idp;
+
+ idp = silc_id_payload_parse(buffer);
+ if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
break;
- silc_client_receive_new_id(client, sock, id_string);
- silc_free(id_string);
+ silc_client_receive_new_id(client, sock, idp);
+ silc_id_payload_free(idp);
break;
}
silc_free(msg);
}
+/* Called when notify is received and some async operation (such as command)
+ is required before processing the notify message. This calls again the
+ silc_client_notify_by_server and reprocesses the original notify packet. */
+
+static void silc_client_notify_by_server_pending(void *context)
+{
+ SilcPacketContext *p = (SilcPacketContext *)context;
+ silc_client_notify_by_server(p->context, p->sock, p);
+ if (p->src_id)
+ silc_free(p->src_id);
+ if (p->dst_id)
+ silc_free(p->dst_id);
+ silc_buffer_free(p->buffer);
+ silc_free(p);
+}
+
/* Received notify message from server */
void silc_client_notify_by_server(SilcClient client,
SilcSocketConnection sock,
- SilcBuffer message)
+ SilcPacketContext *packet)
{
+ SilcBuffer buffer = packet->buffer;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcNotifyPayload payload;
SilcNotifyType type;
SilcClientID *client_id = NULL;
SilcChannelID *channel_id = NULL;
- SilcIDPayload idp;
SilcClientEntry client_entry;
+ SilcClientEntry client_entry2;
SilcChannelEntry channel;
SilcIDCacheEntry id_cache = NULL;
unsigned char *tmp;
- unsigned int tmp_len;
+ unsigned int tmp_len, mode;
- payload = silc_notify_payload_parse(message);
+ payload = silc_notify_payload_parse(buffer);
type = silc_notify_get_type(payload);
args = silc_notify_get_args(payload);
+ if (!args)
+ goto out;
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
+ /* Notify application */
+ client->ops->notify(client, conn, type,
+ silc_argument_get_arg_type(args, 1, NULL));
break;
+
case SILC_NOTIFY_TYPE_INVITE:
/*
- * Someone invited me to a channel. Nothing interesting to do here.
+ * Someone invited me to a channel. Find Client and Channel entries
+ * for the application.
*/
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry and if not found query it */
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* XXX Will ALWAYS fail because currently we don't have way to resolve
+ channel information for channel that we're not joined to. */
+ /* XXX ways to fix: use (extended) LIST command, or define the channel
+ name to the notfy type when name resolving is not mandatory. */
+ /* Find channel entry */
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ goto out;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_JOIN:
/*
* Someone has joined to a channel. Get their ID and nickname and
* cache them for later use.
*/
- /* Get client ID (it's in ID payload) */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- client_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
+ if (!tmp)
+ goto out;
- /* If it's my ID, ignore */
- if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
- break;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
- /* Check if we have that ID already */
- if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
- SILC_ID_CLIENT, &id_cache)) {
- /* Add client to cache */
- client_entry = silc_calloc(1, sizeof(*client_entry));
- client_entry->id = client_id;
- client_entry->nickname =
- strdup(silc_argument_get_arg_type(args, 2, NULL));
- silc_idcache_add(conn->client_cache, client_entry->nickname,
- SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
- client_id = NULL;
- } else {
- client_entry = (SilcClientEntry)id_cache->context;
+ /* Find Client entry and if not found query it */
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
}
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
/* Add client to channel */
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == NULL) {
- channel->clients[channel->clients_count] = client_entry;
+ if (channel->clients[i].client == NULL) {
+ channel->clients[channel->clients_count].client = client_entry;
channel->clients_count++;
break;
}
channel->clients = silc_realloc(channel->clients,
sizeof(*channel->clients) *
(channel->clients_count + 1));
- channel->clients[channel->clients_count] = client_entry;
+ channel->clients[channel->clients_count].client = client_entry;
+ channel->clients[channel->clients_count].mode = 0;
channel->clients_count++;
}
/* XXX add support for multiple same nicks on same channel. Check
for them here */
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_LEAVE:
/*
* Someone has left a channel. We will remove it from the channel but
* we'll keep it in the cache in case we'll need it later.
*/
- /* Get nickname */
- /* XXX Protocol must be changed to send Client ID */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
- break;
-
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
-
+
channel = (SilcChannelEntry)id_cache->context;
-
+
/* Remove client from channel */
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == client_entry) {
- channel->clients[i] = NULL;
+ if (channel->clients[i].client == client_entry) {
+ channel->clients[i].client = NULL;
channel->clients_count--;
break;
}
}
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_SIGNOFF:
/*
- * Someone left SILC. We'll remove it from the channel and from cache.
+ * Someone left SILC. We'll remove it from all channels and from cache.
*/
- /* Get nickname */
- /* XXX Protocol must be changed to send Client ID */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
- break;
-
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
- if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
- SILC_ID_CHANNEL, &id_cache))
- break;
-
- channel = (SilcChannelEntry)id_cache->context;
-
- /* Remove client from channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == client_entry) {
- channel->clients[i] = NULL;
- channel->clients_count--;
- break;
- }
- }
+ goto out;
+
+ /* Remove from all channels */
+ silc_client_remove_from_channels(client, conn, client_entry);
/* Remove from cache */
silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
client_entry->id);
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry);
+
+ /* Free data */
+ if (client_entry->nickname)
+ silc_free(client_entry->nickname);
+ if (client_entry->server)
+ silc_free(client_entry->server);
+ if (client_entry->id)
+ silc_free(client_entry->id);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
break;
+
case SILC_NOTIFY_TYPE_TOPIC_SET:
/*
- * Someone set the topic on a channel. Nothing interesting to do here.
+ * Someone set the topic on a channel.
*/
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Get topic */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, tmp, channel);
break;
+
case SILC_NOTIFY_TYPE_NICK_CHANGE:
/*
- * Someone changed their nickname. Cache the new Client ID.
+ * Someone changed their nickname. If we don't have entry for the new
+ * ID we will query it and return here after it's done. After we've
+ * returned we fetch the old entry and free it and notify the
+ * application.
*/
- /* XXX Protocol must be changed to send the old Client ID and the
- new Client ID. Now we get only nickname, thus, we'll make NAMES
- to receive the new ID. Other choice is to do IDENTIFY but I'm
- doing NAMES for now. */
+ /* Get new Client ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get nickname */
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Ignore my ID */
+ if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
+ break;
+
+ /* Find Client entry and if not found query it */
+ client_entry2 =
+ silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry2) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
+ }
+
+ /* Get old Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find old Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Remove the old from cache */
+ silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
+ client_entry->id);
+
+ /* Replace old ID entry with new one on all channels. */
+ silc_client_replace_from_channels(client, conn, client_entry,
+ client_entry2);
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry, client_entry2);
+
+ /* Free data */
+ if (client_entry->nickname)
+ silc_free(client_entry->nickname);
+ if (client_entry->server)
+ silc_free(client_entry->server);
+ if (client_entry->id)
+ silc_free(client_entry->id);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
+ break;
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ /*
+ * Someone changed a channel mode
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
+ goto out;
+
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
break;
-
- /* Get Channel ID (it's in ID payload) */
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Save the new mode */
+ channel->mode = mode;
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, mode, channel);
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ /*
+ * Someone changed user's mode on a channel
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Get the mode */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ if (!tmp)
+ goto out;
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get target Client ID */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ silc_free(client_id);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find target Client entry */
+ client_entry2 =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry2)
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
-
+
channel = (SilcChannelEntry)id_cache->context;
-
- {
- SilcClientCommandContext ctx;
- char names[512];
-
- ctx = silc_calloc(1, sizeof(*ctx));
- ctx->client = client;
- ctx->conn = conn;
- ctx->command = silc_client_command_find("NAMES");
- memset(names, 0, sizeof(names));
- snprintf(names, sizeof(names), "NAMES %s", channel->channel_name);
- silc_parse_command_line(names, &ctx->argv, &ctx->argv_lens,
- &ctx->argv_types, &ctx->argc, 2);
- ctx->command->cb(ctx);
+
+ /* Save the mode */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == client_entry2) {
+ channel->clients[i].mode = mode;
+ break;
+ }
}
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, mode,
+ client_entry2, channel);
break;
+
+ case SILC_NOTIFY_TYPE_MOTD:
+ /*
+ * Received Message of the day
+ */
+
+ /* Get motd */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, tmp);
+ break;
+
default:
break;
}
- client->ops->notify(client, conn, payload);
+ out:
silc_notify_payload_free(payload);
if (client_id)
silc_free(client_id);
void silc_client_receive_new_id(SilcClient client,
SilcSocketConnection sock,
- unsigned char *id_string)
+ SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
/* Save the new ID */
if (conn->local_id)
silc_free(conn->local_id);
- conn->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
if (conn->local_id_data)
silc_free(conn->local_id_data);
- conn->local_id_data =
- silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
- memcpy(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN);
- conn->local_id_data_len = SILC_ID_CLIENT_LEN;
+
+ conn->local_id = silc_id_payload_get_id(idp);
+ conn->local_id_data = silc_id_payload_get_data(idp);
+ conn->local_id_data_len = silc_id_payload_get_len(idp);;
+
if (!conn->local_entry)
conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+
conn->local_entry->nickname = conn->nickname;
+ if (!conn->local_entry->username) {
+ conn->local_entry->username =
+ silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
+ sizeof(conn->local_entry->username));
+ sprintf(conn->local_entry->username, "%s@%s", client->username,
+ client->hostname);
+ }
conn->local_entry->id = conn->local_id;
/* Put it to the ID cache */
void silc_client_new_channel_id(SilcClient client,
SilcSocketConnection sock,
char *channel_name,
- unsigned int mode,
- unsigned char *id_string)
+ unsigned int mode, SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcChannelID *id;
SilcChannelEntry channel;
SILC_LOG_DEBUG(("New channel ID"));
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
channel = silc_calloc(1, sizeof(*channel));
channel->channel_name = channel_name;
- channel->id = id;
+ channel->id = silc_id_payload_get_id(idp);
channel->mode = mode;
conn->current_channel = channel;
-
+
/* Put it to the ID cache */
silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
- (void *)id, (void *)channel, TRUE);
+ (void *)channel->id, (void *)channel, TRUE);
}
/* Processes received key for channel. The received key will be used
SilcBuffer packet)
{
unsigned char *id_string, *key, *cipher;
- unsigned int key_len;
+ unsigned int tmp_len;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcChannelID *id;
SilcIDCacheEntry id_cache = NULL;
if (!payload)
return;
- id_string = silc_channel_key_get_id(payload, NULL);
+ id_string = silc_channel_key_get_id(payload, &tmp_len);
if (!id_string) {
silc_channel_key_payload_free(payload);
return;
}
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ id = silc_id_payload_parse_id(id_string, tmp_len);
/* Find channel. */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
SILC_ID_CHANNEL, &id_cache))
goto out;
-
+
/* Save the key */
- key = silc_channel_key_get_key(payload, &key_len);
+ key = silc_channel_key_get_key(payload, &tmp_len);
cipher = silc_channel_key_get_cipher(payload, NULL);
channel = (SilcChannelEntry)id_cache->context;
- channel->key_len = key_len;
- channel->key = silc_calloc(key_len, sizeof(*channel->key));
- memcpy(channel->key, key, key_len);
+ channel->key_len = tmp_len;
+ channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
+ memcpy(channel->key, key, tmp_len);
- silc_cipher_alloc(cipher, &channel->channel_key);
- if (!channel->channel_key) {
+ if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
client->ops->say(client, conn,
"Cannot talk to channel: unsupported cipher %s", cipher);
goto out;
}
channel->channel_key->cipher->set_key(channel->channel_key->context,
- key, key_len);
+ key, tmp_len);
/* Client is now joined to the channel */
channel->on_channel = TRUE;
/* Find nickname */
nickname = "[unknown]";
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] &&
- !SILC_ID_CLIENT_COMPARE(channel->clients[i]->id, client_id))
- nickname = channel->clients[i]->nickname;
+ if (channel->clients[i].client &&
+ !SILC_ID_CLIENT_COMPARE(channel->clients[i].client->id, client_id))
+ nickname = channel->clients[i].client->nickname;
}
/* Pass the message to application */
/* Allocate client entry */
remote_client = silc_calloc(1, sizeof(*remote_client));
remote_client->id = remote_id;
- remote_client->nickname = strdup(nickname);
+ silc_parse_nickname(nickname, &remote_client->nickname,
+ &remote_client->server, &remote_client->num);
/* Save the client to cache */
silc_idcache_add(conn->client_cache, remote_client->nickname,
silc_free(message);
silc_free(nickname);
}
+
+/* Removes a client entry from all channel it has joined. This really is
+ a performance killer (client_entry should have pointers to channel
+ entry list). */
+
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list;
+ SilcChannelEntry channel;
+ int i;
+
+ if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+ SILC_ID_CHANNEL, &list))
+ return;
+
+ silc_idcache_list_first(list, &id_cache);
+ channel = (SilcChannelEntry)id_cache->context;
+
+ while (channel) {
+
+ /* Remove client from channel */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == client_entry) {
+ channel->clients[i].client = NULL;
+ channel->clients_count--;
+ break;
+ }
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+ }
+
+ silc_idcache_list_free(list);
+}
+
+/* Replaces `old' client entries from all channels to `new' client entry.
+ This can be called for example when nickname changes and old ID entry
+ is replaced from ID cache with the new one. If the old ID entry is only
+ updated, then this fucntion needs not to be called. */
+
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry new)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list;
+ SilcChannelEntry channel;
+ int i;
+
+ if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+ SILC_ID_CHANNEL, &list))
+ return;
+
+ silc_idcache_list_first(list, &id_cache);
+ channel = (SilcChannelEntry)id_cache->context;
+
+ while (channel) {
+
+ /* Remove client from channel */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == old) {
+ channel->clients[i].client = new;
+ break;
+ }
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+ }
+
+ silc_idcache_list_free(list);
+}