From: Pekka Riikonen Date: Tue, 10 Oct 2000 07:27:14 +0000 (+0000) Subject: Added LEAVE and SIGNOFF notify types. X-Git-Tag: SILC.0.1~348 X-Git-Url: http://git.silcnet.org/gitweb/?a=commitdiff_plain;h=cacf19856864f708c77487b6682175d15f2c6c88;p=silc.git Added LEAVE and SIGNOFF notify types. --- diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 8987f34e..1c1cd301 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -1259,6 +1259,16 @@ void silc_client_notify_by_server(SilcClient client, SilcNotifyPayload payload; SilcNotifyType type; SilcArgumentPayload args; + int i; + + SilcClientID *client_id = NULL; + SilcChannelID *channel_id = NULL; + SilcIDPayload idp; + SilcClientEntry client_entry; + SilcChannelEntry channel; + SilcIDCacheEntry id_cache = NULL; + unsigned char *tmp; + unsigned int tmp_len; payload = silc_notify_payload_parse(message); type = silc_notify_get_type(payload); @@ -1268,85 +1278,204 @@ void silc_client_notify_by_server(SilcClient client, case SILC_NOTIFY_TYPE_NONE: break; case SILC_NOTIFY_TYPE_INVITE: + /* + * Someone invited me to a channel. Nothing interesting to do here. + */ break; case SILC_NOTIFY_TYPE_JOIN: - { - SilcClientID *client_id; - SilcChannelID *channel_id; - SilcClientEntry new_client; - SilcChannelEntry channel; - SilcIDPayload idp; - SilcBuffer idp_buf; - SilcIDCacheEntry id_cache = NULL; - unsigned char *tmp; - unsigned int tmp_len; - - /* Get client ID (it's in ID payload) */ - tmp = silc_argument_get_arg_type(args, 1, &tmp_len); - idp_buf = silc_buffer_alloc(tmp_len); - silc_buffer_pull_tail(idp_buf, SILC_BUFFER_END(idp_buf)); - silc_buffer_put(idp_buf, tmp, tmp_len); - - /* Parse ID payload and get the ID */ - idp = silc_id_payload_parse(idp_buf); - client_id = silc_id_payload_get_id(idp); - - silc_id_payload_free(idp); - silc_buffer_free(idp_buf); - - /* If it's my ID, ignore */ - if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id)) - break; + /* + * Someone has joined to a channel. Get their ID and nickname and + * cache them for later use. + */ - /* Check if we have that ID already */ - if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id, - SILC_ID_CLIENT, NULL)) - break; + /* Get client ID (it's in ID payload) */ + 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 it's my ID, ignore */ + if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id)) + break; + /* 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 */ - new_client = silc_calloc(1, sizeof(*new_client)); - new_client->id = client_id; - new_client->nickname = + 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, new_client->nickname, - SILC_ID_CLIENT, client_id, (void *)new_client, TRUE); + 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; + } - /* Get Channel ID (it's in ID payload) */ - tmp = silc_argument_get_arg_type(args, 5, &tmp_len); - idp_buf = silc_buffer_alloc(tmp_len); - silc_buffer_pull_tail(idp_buf, SILC_BUFFER_END(idp_buf)); - silc_buffer_put(idp_buf, tmp, tmp_len); + /* 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); - /* Parse ID payload and get the ID */ - idp = silc_id_payload_parse(idp_buf); - channel_id = silc_id_payload_get_id(idp); + /* Find channel entry */ + if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, + SILC_ID_CHANNEL, &id_cache)) + break; - silc_id_payload_free(idp); - silc_buffer_free(idp_buf); + channel = (SilcChannelEntry)id_cache->context; - /* Find channel entry */ - if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - SILC_ID_CHANNEL, &id_cache)) + /* Add client to channel */ + for (i = 0; i < channel->clients_count; i++) { + if (channel->clients[i] == NULL) { + channel->clients[channel->clients_count] = client_entry; + channel->clients_count++; break; + } + } - channel = (SilcChannelEntry)id_cache->context; - - /* Add client to channel */ + if (i == channel->clients_count) { channel->clients = silc_realloc(channel->clients, sizeof(*channel->clients) * (channel->clients_count + 1)); - channel->clients[channel->clients_count] = new_client; + channel->clients[channel->clients_count] = client_entry; channel->clients_count++; - - /* XXX add support for multiple same nicks on same channel. Check - for them here */ } + + /* XXX add support for multiple same nicks on same channel. Check + for them here */ 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 */ + 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 (!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; + } + } break; case SILC_NOTIFY_TYPE_SIGNOFF: + /* + * Someone left SILC. We'll remove it from the channel and from cache. + */ + + /* Get nickname */ + /* XXX Protocol must be changed to send 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 (!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; + } + } + + /* Remove from cache */ + silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, + client_entry->id); break; case SILC_NOTIFY_TYPE_TOPIC_SET: + /* + * Someone set the topic on a channel. Nothing interesting to do here. + */ + break; + case SILC_NOTIFY_TYPE_NICK_CHANGE: + /* + * Someone changed their nickname. Cache the new Client ID. + */ + + /* 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 nickname */ + 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 (!client_entry) + break; + + /* Get Channel ID (it's in ID payload) */ + 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 (!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); + } break; default: break; @@ -1354,6 +1483,10 @@ void silc_client_notify_by_server(SilcClient client, client->ops->notify(client, conn, payload); silc_notify_payload_free(payload); + if (client_id) + silc_free(client_id); + if (channel_id) + silc_free(channel_id); } /* Processes the received new Client ID from server. Old Client ID is @@ -1531,15 +1664,9 @@ void silc_client_channel_message(SilcClient client, } /* Pass the message to application */ - if (packet->src_id_type == SILC_ID_CLIENT) { - client->ops->channel_message(client, conn, nickname, - channel->channel_name, - silc_channel_get_data(payload, NULL)); - } else { - /* Message from server */ - /* XXX maybe this should be passed to app... */ - client->ops->say(client, conn, "%s", silc_channel_get_data(payload, NULL)); - } + client->ops->channel_message(client, conn, nickname, + channel->channel_name, + silc_channel_get_data(payload, NULL)); out: if (id) @@ -1588,6 +1715,7 @@ void silc_client_private_message(SilcClient client, if (!remote_id) goto out; + /* If it's me, ignore */ if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id)) goto out; diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index d0218009..66611402 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -878,12 +878,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(names) list_count++; } + /* Remove old client list from channel, if exists */ if (channel->clients) { silc_free(channel->clients); channel->clients = NULL; channel->clients_count = 0; } + /* Allocate room for clients in the channel */ + channel->clients = silc_calloc(list_count, sizeof(*channel->clients)); + /* Cache the received name list and client ID's. This cache expires whenever server sends notify message to channel. It means two things; some user has joined or leaved the channel. */ @@ -898,21 +902,27 @@ SILC_CLIENT_CMD_REPLY_FUNC(names) client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT); silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN); - client = silc_calloc(1, sizeof(*client)); - client->id = client_id; - client->nickname = nickname; + /* Check if we have this client cached already. */ + if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id, + SILC_ID_CLIENT, &id_cache)) { + client = silc_calloc(1, sizeof(*client)); + client->id = client_id; + client->nickname = nickname; - /* Add client to cache */ - silc_idcache_add(conn->client_cache, nickname, SILC_ID_CLIENT, - client_id, (void *)client, TRUE); - name_list = name_list + nick_len + 1; + /* Add client to cache */ + silc_idcache_add(conn->client_cache, nickname, SILC_ID_CLIENT, + client_id, (void *)client, TRUE); + } else { + client = (SilcClientEntry)id_cache->context; + silc_free(client_id); + silc_free(nickname); + id_cache = NULL; + } - /* Add client to channel */ - channel->clients = silc_realloc(channel->clients, - sizeof(*channel->clients) * - (channel->clients_count + 1)); channel->clients[channel->clients_count] = client; channel->clients_count++; + + name_list += nick_len + 1; } name_list = cp;