/*
- client_notify.c
+ client_notify.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2002 Pekka Riikonen
+ Copyright (C) 1997 - 2005 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
important packets sent by the server. They tell different things to the
client such as nick changes, mode changes etc. */
-#include "silcincludes.h"
+#include "silc.h"
#include "silcclient.h"
#include "client_internal.h"
} *SilcClientNotifyResolve;
SILC_TASK_CALLBACK(silc_client_notify_check_client)
-{
+{
SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
SilcClient client = res->context;
SilcClientConnection conn = res->sock->user_data;
SilcClientID *client_id = res->packet;
- silc_client_get_client_by_id_resolve(client, conn, client_id, NULL, NULL);
+ silc_client_get_client_by_id_resolve(client, conn, client_id,
+ NULL, NULL, NULL);
silc_free(client_id);
silc_socket_free(res->sock);
silc_free(res);
static void silc_client_notify_by_server_pending(void *context, void *context2)
{
SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
- SilcClientCommandReplyContext reply =
+ SilcClientCommandReplyContext reply =
(SilcClientCommandReplyContext)context2;
SILC_LOG_DEBUG(("Start"));
}
}
-/* Attaches to the channel's resolving cmd ident and calls the
+/* Attaches to the channel's resolving cmd ident and calls the
notify handling with `packet' after it's received. */
static void silc_client_channel_wait(SilcClient client,
silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
silc_client_command_reply_identify_i, 0,
++conn->cmd_ident);
- silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+ silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
conn->cmd_ident, 1, 5, idp->data, idp->len);
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
silc_client_notify_by_server_pending, res);
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
/* Notify application */
- client->internal->ops->notify(client, conn, type,
+ client->internal->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. Find Client and Channel entries
* for the application.
*/
-
+
SILC_LOG_DEBUG(("Notify: INVITE"));
/* Get Channel ID */
/* Find Client entry and if not found query it */
client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
goto out;
/* Notify application */
- client->internal->ops->notify(client, conn, type, channel, tmp,
+ client->internal->ops->notify(client, conn, type, channel, tmp,
client_entry);
break;
SILC_LOG_DEBUG(("Notify: JOIN"));
+ /* 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, NULL);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ break;
+
/* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
/* Find Client entry and if not found query it */
client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
/* If nickname or username hasn't been resolved, do so */
if (!client_entry->nickname || !client_entry->username) {
if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
- client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
goto out;
}
- silc_client_notify_by_server_resolve(client, conn, packet,
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
client_entry->resolve_cmd_ident = conn->cmd_ident;
silc_client_nickname_format(client, conn, client_entry);
}
- /* 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, NULL);
- if (!channel_id)
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
goto out;
-
- /* Get channel entry */
- channel = silc_client_get_channel_by_id(client, conn, channel_id);
- if (!channel)
- break;
+ }
/* Join the client to channel */
if (!silc_client_on_channel(channel, client_entry)) {
* 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.
*/
-
+
SILC_LOG_DEBUG(("Notify: LEAVE"));
/* Get Client ID */
goto out;
/* Find Client entry */
- client_entry =
+ client_entry =
silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
}
/* Some client implementations actually quit network by first doing
- LEAVE and then immediately SIGNOFF. We'll check for this by doing
+ LEAVE and then immediately SIGNOFF. We'll check for this by doing
check for the client after 5 - 34 seconds. If it is not valid after
that we'll remove the client from cache. */
if (!silc_hash_table_count(client_entry->channels)) {
goto out;
/* Find Client entry */
- client_entry =
+ client_entry =
silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
- /* Remove from all channels */
- silc_client_remove_from_channels(client, conn, client_entry);
-
- /* Remove from cache */
- silc_idcache_del_by_context(conn->client_cache, client_entry);
-
/* Get signoff message */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
if (tmp_len > 128)
/* Notify application */
client->internal->ops->notify(client, conn, type, client_entry, tmp);
+ /* Remove from all channels */
+ silc_client_remove_from_channels(client, conn, client_entry);
+
+ /* Remove from cache */
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
+
/* Free data */
silc_client_del_client_entry(client, conn, client_entry);
break;
if (!client_entry) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
if (!server) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_SERVER, server_id);
server = silc_client_add_server(client, conn, NULL, NULL, server_id);
if (!server)
res->packet = silc_packet_context_dup(packet);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
server->resolve_cmd_ident,
silc_client_notify_by_server_pending, res);
goto out;
}
-
+
/* Save the pointer to the client_entry pointer */
client_entry = (SilcClientEntry)server;
} else {
if (!client_entry) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CHANNEL, channel_id);
goto out;
}
goto out;
}
+ if (tmp) {
+ silc_free(channel->topic);
+ channel->topic = silc_memdup(tmp, strlen(tmp));
+ }
+
/* 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. */
/*
* 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
+ * returned we fetch the old entry and free it and notify the
* application.
*/
if (!client_entry)
goto out;
silc_free(client_id);
+ client_id = NULL;
+
+ /* Wait for resolving if necessary */
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending, res);
+ goto out;
+ }
client_entry->valid = FALSE;
if (!client_id)
goto out;
- /* From protocol version 1.1 we get the new nickname in notify as well,
- so we don't have to resolve it. Do it the hard way if server doesn't
- send it to us. */
+ /* Take the nickname */
tmp = silc_argument_get_arg_type(args, 3, NULL);
- if (tmp) {
- /* Protocol version 1.1 */
- char *tmp_nick = NULL;
-
- /* Check whether nickname changed at all. It is possible that nick
- change notify is received but nickname didn't changed, only the
- ID changes. */
- if (client->internal->params->nickname_parse)
- client->internal->params->nickname_parse(client_entry->nickname,
- &tmp_nick);
- else
- tmp_nick = strdup(tmp);
-
- if (tmp_nick && !strcmp(tmp, tmp_nick)) {
- /* Nickname didn't change. Update only the ID */
- silc_idcache_del_by_context(conn->client_cache, client_entry);
- silc_free(client_entry->id);
- client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
- silc_idcache_add(conn->client_cache, strdup(tmp),
- client_entry->id, client_entry, 0, NULL);
-
- /* Notify application */
- client->internal->ops->notify(client, conn, type,
- client_entry, client_entry);
- break;
- }
- silc_free(tmp_nick);
-
- /* Create new client entry, and save all old information with the
- new nickname and client ID */
- client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
- client_entry->realname,
- silc_id_dup(client_id,
- SILC_ID_CLIENT), 0);
- if (!client_entry2)
- goto out;
+ if (!tmp)
+ goto out;
- if (client_entry->server)
- client_entry2->server = strdup(client_entry->server);
- if (client_entry->username)
- client_entry2->username = strdup(client_entry->username);
- if (client_entry->hostname)
- client_entry2->hostname = strdup(client_entry->hostname);
- silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
- client_entry->mode);
- } else {
- /* Protocol version 1.0 */
+ /* Check whether nickname changed at all. It is possible that nick
+ change notify is received but nickname didn't change, only the
+ ID changes. Check whether the hashes in the Client ID match, if
+ they do nickname didn't change. */
+ if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
+ silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
+ /* Nickname didn't change. Update only Client ID. */
+
+ /* Normalize nickname */
+ tmp = silc_identifier_check(tmp, strlen(tmp),
+ SILC_STRING_UTF8, 128, NULL);
+ if (!tmp)
+ goto out;
- /* Find client entry and if not found resolve it */
- client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry2) {
- /* Resolve the entry information */
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CLIENT, client_id);
+ silc_idcache_del_by_context(conn->internal->client_cache,
+ client_entry);
+ silc_free(client_entry->id);
+ client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
+ silc_idcache_add(conn->internal->client_cache, tmp,
+ client_entry->id, client_entry, 0, NULL);
+
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type,
+ client_entry, client_entry);
+ break;
+ }
- /* Add the new entry even though we resolved it. This is because we
- want to replace the old entry with the new entry here right now. */
- client_entry2 =
- silc_client_add_client(client, conn, NULL, NULL, NULL,
- silc_id_dup(client_id, SILC_ID_CLIENT),
- client_entry->mode);
-
- /* Replace old ID entry with new one on all channels. */
- silc_client_replace_from_channels(client, conn, client_entry,
- client_entry2);
- break;
- }
+ /* Create new client entry, and save all old information with the
+ new nickname and client ID */
+ client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
+ client_entry->realname,
+ silc_id_dup(client_id,
+ SILC_ID_CLIENT), 0);
+ if (!client_entry2)
+ goto out;
- if (client_entry2 != conn->local_entry)
- silc_client_nickname_format(client, conn, client_entry2);
- }
+ if (client_entry->server)
+ client_entry2->server = strdup(client_entry->server);
+ if (client_entry->username)
+ client_entry2->username = strdup(client_entry->username);
+ if (client_entry->hostname)
+ client_entry2->hostname = strdup(client_entry->hostname);
+ client_entry2->fingerprint = client_entry->fingerprint;
+ client_entry2->fingerprint_len = client_entry->fingerprint_len;
+ client_entry->fingerprint = NULL;
+ client_entry->fingerprint_len = 0;
+ silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
+ client_entry->mode);
/* Remove the old from cache */
- silc_idcache_del_by_context(conn->client_cache, client_entry);
-
+ silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
+
/* Replace old ID entry with new one on all channels. */
silc_client_replace_from_channels(client, conn, client_entry,
client_entry2);
/* Notify application */
- client->internal->ops->notify(client, conn, type,
+ client->internal->ops->notify(client, conn, type,
client_entry, client_entry2);
-
+
/* Free old client entry */
silc_client_del_client_entry(client, conn, client_entry);
break;
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
- /*
- * Someone changed a channel mode
- */
+ {
+ /*
+ * Someone changed a channel mode
+ */
+ char *passphrase, *cipher, *hmac;
+ SilcPublicKey founder_key = NULL;
+ SilcBufferStruct chpks;
- SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+ SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
- /* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
- SILC_ID_CHANNEL);
- if (!channel_id)
- goto out;
- channel = silc_client_get_channel_by_id(client, conn, channel_id);
- if (!channel)
- goto out;
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
+ channel = silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!channel)
+ goto out;
- /* Get ID */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp)
- goto out;
- id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
- if (!id)
- goto out;
+ /* Get ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+ if (!id)
+ goto out;
- /* Find Client entry */
- if (id_type == SILC_ID_CLIENT) {
/* Find Client entry */
- client_id = id;
- client_entry = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CLIENT, client_id);
- goto out;
- }
- } else if (id_type == SILC_ID_SERVER) {
- /* Find Server entry */
- server_id = id;
- server = silc_client_get_server_by_id(client, conn, server_id);
- if (!server) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_SERVER, server_id);
- server = silc_client_add_server(client, conn, NULL, NULL, server_id);
- if (!server)
+ if (id_type == SILC_ID_CLIENT) {
+ /* Find Client entry */
+ client_id = id;
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
goto out;
+ }
- server->resolve_cmd_ident = conn->cmd_ident;
- server_id = NULL;
- goto out;
+ if (!client_entry->nickname) {
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ client_entry->resolve_cmd_ident = conn->cmd_ident;
+ goto out;
+ }
+ } else if (id_type == SILC_ID_SERVER) {
+ /* Find Server entry */
+ server_id = id;
+ server = silc_client_get_server_by_id(client, conn, server_id);
+ if (!server) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_SERVER, server_id);
+ server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+ if (!server)
+ goto out;
+
+ server->resolve_cmd_ident = conn->cmd_ident;
+ server_id = NULL;
+ goto out;
+ }
+
+ /* If entry being resoled, wait for it before processing this notify */
+ if (server->resolve_cmd_ident) {
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ server->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Save the pointer to the client_entry pointer */
+ client_entry = (SilcClientEntry)server;
+ } else {
+ /* Find Channel entry */
+ silc_free(channel_id);
+ channel_id = id;
+ client_entry = (SilcClientEntry)
+ silc_client_get_channel_by_id(client, conn, channel_id);
+ if (!client_entry) {
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CHANNEL, channel_id);
+ goto out;
+ }
}
- /* If entry being resoled, wait for it before processing this notify */
- if (server->resolve_cmd_ident) {
- SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
- res->packet = silc_packet_context_dup(packet);
- res->context = client;
- res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
- server->resolve_cmd_ident,
- silc_client_notify_by_server_pending, res);
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
goto out;
- }
-
- /* Save the pointer to the client_entry pointer */
- client_entry = (SilcClientEntry)server;
- } else {
- /* Find Channel entry */
- silc_free(channel_id);
- channel_id = id;
- client_entry = (SilcClientEntry)
- silc_client_get_channel_by_id(client, conn, channel_id);
- if (!client_entry) {
- silc_client_channel_set_wait(client, conn, channel,
- conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CHANNEL, channel_id);
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* If information is being resolved for this channel, wait for it */
+ if (channel->resolve_cmd_ident) {
+ silc_client_channel_wait(client, conn, channel, packet);
goto out;
}
- }
- /* Get the mode */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (!tmp)
- goto out;
+ /* Save the new mode */
+ channel->mode = mode;
- SILC_GET32_MSB(mode, tmp);
+ /* Get the cipher */
+ cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
- /* If information is being resolved for this channel, wait for it */
- if (channel->resolve_cmd_ident) {
- silc_client_channel_wait(client, conn, channel, packet);
- goto out;
- }
+ /* Get the hmac */
+ hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (hmac) {
+ unsigned char hash[SILC_HASH_MAXLEN];
- /* Save the new mode */
- channel->mode = mode;
+ if (channel->hmac)
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
+ goto out;
- /* Get the hmac */
- tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
- if (tmp) {
- unsigned char hash[32];
+ silc_hash_make(silc_hmac_get_hash(channel->hmac),
+ channel->key, channel->key_len / 8,
+ hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+ memset(hash, 0, sizeof(hash));
+ }
- if (channel->hmac)
- silc_hmac_free(channel->hmac);
- if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
- goto out;
+ /* Get the passphrase if it was set */
+ passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
- silc_hash_make(silc_hmac_get_hash(channel->hmac),
- channel->key, channel->key_len / 8,
- hash);
- silc_hmac_set_key(channel->hmac, hash,
- silc_hash_len(silc_hmac_get_hash(channel->hmac)));
- memset(hash, 0, sizeof(hash));
- }
+ /* Get the channel founder key if it was set */
+ tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+ if (tmp) {
+ if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
+ founder_key = NULL;
+ }
- /* 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->internal->ops->notify(client, conn, type, id_type,
- client_entry, mode, NULL, tmp, channel);
+ /* Get user limit */
+ tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
+ if (tmp && tmp_len == 4)
+ SILC_GET32_MSB(channel->user_limit, tmp);
+ if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
+ channel->user_limit = 0;
+
+ /* Get the channel public key that was added or removed */
+ tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+ if (tmp)
+ silc_buffer_set(&chpks, tmp, tmp_len);
+
+ /* 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->internal->ops->notify(client, conn, type, id_type,
+ client_entry, mode, cipher, hmac,
+ passphrase, founder_key,
+ tmp ? &chpks : NULL, channel);
+
+ if (founder_key)
+ silc_pkcs_public_key_free(founder_key);
+ }
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
if (!client_entry) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
+
+ if (!client_entry->nickname) {
+ if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+ /* Attach to existing resolving */
+ SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+ res->packet = silc_packet_context_dup(packet);
+ res->context = client;
+ res->sock = silc_socket_dup(conn->sock);
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ client_entry->resolve_cmd_ident,
+ silc_client_notify_by_server_pending,
+ res);
+ goto out;
+ }
+
+ /* Do new resolving */
+ silc_client_channel_set_wait(client, conn, channel,
+ conn->cmd_ident + 1);
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+ client_entry->resolve_cmd_ident = conn->cmd_ident;
+ goto out;
+ }
} else if (id_type == SILC_ID_SERVER) {
/* Find Server entry */
server_id = id;
if (!server) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_SERVER, server_id);
server = silc_client_add_server(client, conn, NULL, NULL, server_id);
if (!server)
res->packet = silc_packet_context_dup(packet);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
server->resolve_cmd_ident,
silc_client_notify_by_server_pending, res);
goto out;
if (!client_entry) {
silc_client_channel_set_wait(client, conn, channel,
conn->cmd_ident + 1);
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CHANNEL, channel_id);
goto out;
}
goto out;
/* Find target Client entry */
- client_entry2 =
+ client_entry2 =
silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry2) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
is for channel but application don't know it from the arguments
sent by server. */
client->internal->ops->notify(client, conn, type,
- id_type, client_entry, mode,
+ id_type, client_entry, mode,
client_entry2, channel);
break;
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
goto out;
-
+
/* Notify application */
client->internal->ops->notify(client, conn, type, tmp);
break;
goto out;
silc_free(channel_id);
+ channel_id = NULL;
/* Get the new ID */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
/* Find kicker's client entry and if not found resolve it */
client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry2) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
} else {
/* Get comment */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ /* Remove kicked client from channel */
+ if (client_entry != conn->local_entry) {
+ chu = silc_client_on_channel(channel, client_entry);
+ if (chu) {
+ silc_hash_table_del(client_entry->channels, channel);
+ silc_hash_table_del(channel->user_list, client_entry);
+ silc_free(chu);
+ }
+ }
+
/* 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->internal->ops->notify(client, conn, type, client_entry, tmp,
+ client->internal->ops->notify(client, conn, type, client_entry, tmp,
client_entry2, channel);
- /* Remove kicked client from channel */
+ /* Remove kicked client (us) from channel */
if (client_entry == conn->local_entry) {
/* If I was kicked from channel, remove the channel */
if (conn->current_channel == channel)
conn->current_channel = NULL;
silc_client_del_channel(client, conn, channel);
} else {
- chu = silc_client_on_channel(channel, client_entry);
- if (chu) {
- silc_hash_table_del(client_entry->channels, channel);
- silc_hash_table_del(channel->user_list, client_entry);
- silc_free(chu);
- }
-
if (!silc_hash_table_count(client_entry->channels)) {
SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
res->context = client;
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
if (tmp) {
silc_free(client_id);
+ client_id = NULL;
id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
if (!id)
goto out;
if (id_type == SILC_ID_CLIENT) {
/* Find Client entry */
client_id = id;
- client_entry2 = silc_client_get_client_by_id(client, conn,
+ client_entry2 = silc_client_get_client_by_id(client, conn,
client_id);
if (!client_entry) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
server_id = id;
server = silc_client_get_server_by_id(client, conn, server_id);
if (!server) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_SERVER, server_id);
server = silc_client_add_server(client, conn, NULL, NULL,
server_id);
res->packet = silc_packet_context_dup(packet);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
- silc_client_command_pending(conn, SILC_COMMAND_NONE,
+ silc_client_command_pending(conn, SILC_COMMAND_NONE,
server->resolve_cmd_ident,
silc_client_notify_by_server_pending,
res);
goto out;
}
-
+
/* Save the pointer to the client_entry pointer */
client_entry2 = (SilcClientEntry)server;
} else {
channel_id = id;
channel = silc_client_get_channel_by_id(client, conn, channel_id);
if (!channel) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CHANNEL, channel_id);
goto out;
}
-
+
/* Save the pointer to the client_entry pointer */
client_entry2 = (SilcClientEntry)channel;
silc_free(channel_id);
}
/* Notify application. */
- client->internal->ops->notify(client, conn, type, client_entry,
+ client->internal->ops->notify(client, conn, type, client_entry,
comment, id_type, client_entry2);
if (client_entry != conn->local_entry)
silc_client_del_client(client, conn, client_entry);
}
break;
-
+
case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
{
/*
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!client_id)
goto out;
-
+
/* Get the client entry */
client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (client_entry) {
- clients = silc_realloc(clients, sizeof(*clients) *
+ clients = silc_realloc(clients, sizeof(*clients) *
(clients_count + 1));
clients[clients_count] = client_entry;
clients_count++;
/* Notify application. We don't keep server entries so the server
entry is returned as NULL. The client's are returned as array
of SilcClientEntry pointers. */
- client->internal->ops->notify(client, conn, type, NULL,
+ client->internal->ops->notify(client, conn, type, NULL,
clients, clients_count);
for (i = 0; i < clients_count; i++) {
* Received notify about some client we are watching
*/
SilcNotifyType notify = 0;
- bool del_client = FALSE;
+ SilcBool del_client = FALSE;
+ unsigned char *pk;
+ SilcUInt32 pk_len;
+ SilcPublicKey public_key = NULL;
SILC_LOG_DEBUG(("Notify: WATCH"));
/* Find Client entry and if not found query it */
client_entry = silc_client_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- silc_client_notify_by_server_resolve(client, conn, packet,
+ silc_client_notify_by_server_resolve(client, conn, packet,
SILC_ID_CLIENT, client_id);
goto out;
}
/* If same nick, the client was new to us and has become "present"
to network. Send NULL as nick to application. */
- if (tmp_nick && !strcmp(tmp, tmp_nick))
+ if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
tmp = NULL;
silc_free(tmp_nick);
}
+ /* Get public key, if present */
+ pk = silc_argument_get_arg_type(args, 5, &pk_len);
+ if (pk && !client_entry->public_key) {
+ if (silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key)) {
+ client_entry->public_key = public_key;
+ public_key = NULL;
+ }
+ }
+
/* Notify application. */
client->internal->ops->notify(client, conn, type, client_entry,
- tmp, mode, notify);
+ tmp, mode, notify,
+ client_entry->public_key);
client_entry->mode = mode;
silc_client_notify_del_client_cb, res,
1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
+
+ silc_pkcs_public_key_free(public_key);
}
break;