X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient_notify.c;h=f42ebaa6482bc21f6cd9d16e86df364b0d426847;hp=9b825954f2deb2f9618be991fc39f478a84eaa33;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=da3a876c26b6d697ee6446ad81a8edfff1828cab diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 9b825954..f42ebaa6 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -35,11 +35,28 @@ typedef struct { SILC_TASK_CALLBACK(silc_client_notify_check_client) { SilcClientNotifyResolve res = (SilcClientNotifyResolve)context; - SilcClientConnection conn = res->context; - SilcClient client = conn->client; + 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); +} + +SILC_TASK_CALLBACK(silc_client_notify_del_client_cb) +{ + SilcClientNotifyResolve res = (SilcClientNotifyResolve)context; + SilcClient client = res->context; + SilcClientConnection conn = res->sock->user_data; + SilcClientID *client_id = res->packet; + SilcClientEntry client_entry; + client_entry = silc_client_get_client_by_id(client, conn, client_id); + if (client_entry) + silc_client_del_client(client, conn, client_entry); + silc_free(client_id); + silc_socket_free(res->sock); silc_free(res); } @@ -66,6 +83,68 @@ static void silc_client_notify_by_server_pending(void *context, void *context2) silc_free(res); } +/* Resets the channel entry's resolve_cmd_ident after whatever-thing + was resolved is completed. */ + +static void silc_client_channel_cond(void *context, void *context2) +{ + SilcClientNotifyResolve res = (SilcClientNotifyResolve)context; + SilcClient client = res->context; + SilcClientConnection conn = res->sock->user_data; + SilcChannelID *channel_id = res->packet; + SilcChannelEntry channel; + channel = silc_client_get_channel_by_id(client, conn, channel_id); + if (channel) + channel->resolve_cmd_ident = 0; + silc_free(channel_id); + silc_socket_free(res->sock); + silc_free(res); +} + +/* Function that starts waiting for the `cmd_ident' to arrive and + marks the channel info being resolved. */ + +static void silc_client_channel_set_wait(SilcClient client, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcUInt16 cmd_ident) +{ + SilcClientNotifyResolve res; + + if (!channel->resolve_cmd_ident) { + res = silc_calloc(1, sizeof(*res)); + res->context = client; + res->sock = silc_socket_dup(conn->sock); + res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL); + silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident, + silc_client_channel_cond, res); + channel->resolve_cmd_ident = cmd_ident; + } +} + +/* 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, + SilcClientConnection conn, + SilcChannelEntry channel, + SilcPacketContext *packet) +{ + SilcClientNotifyResolve res; + + if (!channel->resolve_cmd_ident) + return; + + 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, + channel->resolve_cmd_ident, + silc_client_notify_by_server_pending, res); +} + /* Resolve client, channel or server information. */ static void silc_client_notify_by_server_resolve(SilcClient client, @@ -87,7 +166,7 @@ static void silc_client_notify_by_server_resolve(SilcClient client, silc_client_command_reply_whois_i, 0, ++conn->cmd_ident); silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident, - 1, 3, idp->data, idp->len); + 1, 4, idp->data, idp->len); silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident, silc_client_notify_by_server_pending, res); } else { @@ -308,10 +387,11 @@ void silc_client_notify_by_server(SilcClient client, that we'll remove the client from cache. */ if (!silc_hash_table_count(client_entry->channels)) { SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res)); - res->context = conn; + res->context = client; + res->sock = silc_socket_dup(conn->sock); res->packet = silc_id_dup(client_id, SILC_ID_CLIENT); - silc_schedule_task_add(client->schedule, 0, - silc_client_notify_check_client, conn, + silc_schedule_task_add(client->schedule, conn->sock->sock, + silc_client_notify_check_client, res, (5 + (silc_rng_get_rn16(client->rng) % 29)), 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); } @@ -348,7 +428,7 @@ void silc_client_notify_by_server(SilcClient client, silc_client_remove_from_channels(client, conn, client_entry); /* Remove from cache */ - silc_idcache_del_by_context(conn->client_cache, client_entry); + silc_idcache_del_by_context(conn->internal->client_cache, client_entry); /* Get signoff message */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); @@ -369,6 +449,15 @@ void silc_client_notify_by_server(SilcClient client, SILC_LOG_DEBUG(("Notify: TOPIC_SET")); + /* 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) + break; + /* Get ID */ tmp = silc_argument_get_arg_type(args, 1, &tmp_len); if (!tmp) @@ -383,6 +472,8 @@ void silc_client_notify_by_server(SilcClient client, 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; @@ -392,8 +483,28 @@ void silc_client_notify_by_server(SilcClient client, 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; } @@ -401,18 +512,17 @@ void silc_client_notify_by_server(SilcClient client, client_entry = (SilcClientEntry)server; } else { /* Find Channel entry */ + silc_free(channel_id); channel_id = id; - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel) { + 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; } - - /* Save the pointer to the client_entry pointer */ - client_entry = (SilcClientEntry)channel; - silc_free(channel_id); - channel_id = NULL; } /* Get topic */ @@ -420,14 +530,11 @@ void silc_client_notify_by_server(SilcClient client, if (!tmp) goto out; - /* Get channel entry */ - channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len, - SILC_ID_CHANNEL); - 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; - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel) - break; + } /* Notify application. The channel entry is sent last as this notify is for channel but application don't know it from the arguments @@ -465,6 +572,19 @@ void silc_client_notify_by_server(SilcClient client, 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; @@ -477,84 +597,54 @@ void silc_client_notify_by_server(SilcClient client, 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 (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 */ + 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); + /* Check whether nickname changed at all. It is possible that nick + change notify is received but nickname didn't changed, 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)) { + /* Nickname didn't change. Update only the 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, strdup(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 = NULL; + 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, @@ -576,6 +666,15 @@ void silc_client_notify_by_server(SilcClient client, 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 ID */ tmp = silc_argument_get_arg_type(args, 1, &tmp_len); if (!tmp) @@ -590,6 +689,30 @@ void silc_client_notify_by_server(SilcClient client, 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; + } + + 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); goto out; @@ -599,27 +722,46 @@ void silc_client_notify_by_server(SilcClient client, 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; - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel) { + 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; } - - /* Save the pointer to the client_entry pointer */ - client_entry = (SilcClientEntry)channel; - silc_free(channel_id); - channel_id = NULL; } /* Get the mode */ @@ -629,14 +771,11 @@ void silc_client_notify_by_server(SilcClient client, SILC_GET32_MSB(mode, tmp); - /* 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) + /* 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; + } /* Save the new mode */ channel->mode = mode; @@ -673,6 +812,15 @@ void silc_client_notify_by_server(SilcClient client, SILC_LOG_DEBUG(("Notify: CUMODE_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) + break; + /* Get ID */ tmp = silc_argument_get_arg_type(args, 1, &tmp_len); if (!tmp) @@ -687,6 +835,30 @@ void silc_client_notify_by_server(SilcClient client, 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; + } + + 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); goto out; @@ -696,8 +868,28 @@ void silc_client_notify_by_server(SilcClient client, 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; } @@ -705,18 +897,17 @@ void silc_client_notify_by_server(SilcClient client, client_entry = (SilcClientEntry)server; } else { /* Find Channel entry */ + silc_free(channel_id); channel_id = id; - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel) { + 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; } - - /* Save the pointer to the client_entry pointer */ - client_entry = (SilcClientEntry)channel; - silc_free(channel_id); - channel_id = NULL; } /* Get the mode */ @@ -726,6 +917,12 @@ void silc_client_notify_by_server(SilcClient client, 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 target Client ID */ tmp = silc_argument_get_arg_type(args, 3, &tmp_len); if (!tmp) @@ -739,17 +936,11 @@ void silc_client_notify_by_server(SilcClient client, /* Find target Client entry */ client_entry2 = silc_client_get_client_by_id(client, conn, client_id); - if (!client_entry2) - goto out; - - /* Get channel entry */ - channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len, - SILC_ID_CHANNEL); - if (!channel_id) + if (!client_entry2) { + silc_client_notify_by_server_resolve(client, conn, packet, + SILC_ID_CLIENT, client_id); goto out; - channel = silc_client_get_channel_by_id(client, conn, channel_id); - if (!channel) - break; + } /* Save the mode */ chu = silc_client_on_channel(channel, client_entry2); @@ -802,6 +993,7 @@ void silc_client_notify_by_server(SilcClient client, goto out; silc_free(channel_id); + channel_id = NULL; /* Get the new ID */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); @@ -812,7 +1004,8 @@ void silc_client_notify_by_server(SilcClient client, goto out; /* Replace the Channel ID */ - silc_client_replace_channel_id(client, conn, channel, channel_id); + if (silc_client_replace_channel_id(client, conn, channel, channel_id)) + channel_id = NULL; /* Notify application */ client->internal->ops->notify(client, conn, type, channel, channel); @@ -890,6 +1083,17 @@ void silc_client_notify_by_server(SilcClient client, 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; + res->sock = silc_socket_dup(conn->sock); + res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT); + silc_schedule_task_add(client->schedule, conn->sock->sock, + silc_client_notify_check_client, res, + (5 + (silc_rng_get_rn16(client->rng) % 529)), + 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + } } break; @@ -924,6 +1128,7 @@ void silc_client_notify_by_server(SilcClient 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; @@ -946,6 +1151,25 @@ void silc_client_notify_by_server(SilcClient client, if (!server) { 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 (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; } @@ -1069,6 +1293,7 @@ void silc_client_notify_by_server(SilcClient client, * Received notify about some client we are watching */ SilcNotifyType notify = 0; + bool del_client = FALSE; SILC_LOG_DEBUG(("Notify: WATCH")); @@ -1114,7 +1339,7 @@ void silc_client_notify_by_server(SilcClient client, /* If same nick, the client was new to us and has become "present" to network. Send NULL as nick to application. */ - if (!strcmp(tmp, tmp_nick)) + if (tmp_nick && !strcmp(tmp, tmp_nick)) tmp = NULL; silc_free(tmp_nick); @@ -1130,7 +1355,22 @@ void silc_client_notify_by_server(SilcClient client, client is on some channel */ if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE && !silc_hash_table_count(client_entry->channels)) - silc_client_del_client(client, conn, client_entry); + del_client = TRUE; + else if (notify == SILC_NOTIFY_TYPE_SIGNOFF || + notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF || + notify == SILC_NOTIFY_TYPE_KILLED) + del_client = TRUE; + + if (del_client) { + SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res)); + res->context = client; + res->sock = silc_socket_dup(conn->sock); + res->packet = client_id; + client_id = NULL; + silc_schedule_task_add(client->schedule, conn->sock->sock, + silc_client_notify_del_client_cb, res, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + } } break;