5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "clientlibincludes.h"
25 SilcClientCommandContext cmd;
26 SilcGetClientCallback completion;
33 SILC_CLIENT_CMD_FUNC(get_client_callback)
35 GetClientInternal i = (GetClientInternal)context;
36 SilcClientEntry *clients;
37 unsigned int clients_count;
40 clients = silc_client_get_clients_local(i->cmd->client, i->cmd->conn,
41 i->nickname, i->server,
44 i->completion(i->cmd->client, i->cmd->conn, clients,
45 clients_count, i->context);
51 static void silc_client_get_client_destructor(void *context)
53 GetClientInternal i = (GetClientInternal)context;
55 if (i->found == FALSE)
56 i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
58 silc_client_command_free(i->cmd);
60 silc_free(i->nickname);
66 /* Finds client entry or entries by the `nickname' and `server'. The
67 completion callback will be called when the client entries has been found.
69 Note: this function is always asynchronous and resolves the client
70 information from the server. Thus, if you already know the client
71 information then use the silc_client_get_client_by_id function to
72 get the client entry since this function may be very slow and should
73 be used only to initially get the client entries. */
75 void silc_client_get_clients(SilcClient client,
76 SilcClientConnection conn,
79 SilcGetClientCallback completion,
83 SilcClientCommandContext ctx;
84 GetClientInternal i = silc_calloc(1, sizeof(*i));
86 /* No ID found. Do query from the server. The query is done by
87 sending simple IDENTIFY command to the server. */
88 ctx = silc_client_command_alloc();
91 ctx->command = silc_client_command_find("IDENTIFY");
92 memset(ident, 0, sizeof(ident));
93 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
94 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
95 &ctx->argv_types, &ctx->argc, 2);
96 ctx->command->cb(ctx);
99 i->nickname = nickname ? strdup(nickname) : NULL;
100 i->server = server ? strdup(server) : NULL;
101 i->completion = completion;
102 i->context = context;
104 /* Add pending callback */
105 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
107 silc_client_get_client_destructor,
108 silc_client_command_get_client_callback,
112 /* Same as above function but does not resolve anything from the server.
113 This checks local cache and returns all clients from the cache. */
115 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
116 SilcClientConnection conn,
119 unsigned int *clients_count)
121 SilcIDCacheEntry id_cache;
122 SilcIDCacheList list = NULL;
123 SilcClientEntry entry, *clients;
126 /* Find ID from cache */
127 if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list))
130 if (!silc_idcache_list_count(list)) {
131 silc_idcache_list_free(list);
135 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
136 *clients_count = silc_idcache_list_count(list);
139 /* Take all without any further checking */
140 silc_idcache_list_first(list, &id_cache);
142 clients[i++] = id_cache->context;
143 if (!silc_idcache_list_next(list, &id_cache))
147 /* Check multiple cache entries for match */
148 silc_idcache_list_first(list, &id_cache);
150 entry = (SilcClientEntry)id_cache->context;
153 strncasecmp(server, entry->server, strlen(server))) {
154 if (!silc_idcache_list_next(list, &id_cache)) {
161 clients[i++] = id_cache->context;
162 if (!silc_idcache_list_next(list, &id_cache))
168 silc_idcache_list_free(list);
173 /* The old style function to find client entry. This is used by the
174 library internally. If `query' is TRUE then the client information is
175 requested by the server. The pending command callback must be set
178 SilcClientEntry silc_idlist_get_client(SilcClient client,
179 SilcClientConnection conn,
185 SilcIDCacheEntry id_cache;
186 SilcIDCacheList list = NULL;
187 SilcClientEntry entry = NULL;
189 /* Find ID from cache */
190 if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
195 SilcClientCommandContext ctx;
197 SILC_LOG_DEBUG(("Requesting Client ID from server"));
199 /* No ID found. Do query from the server. The query is done by
200 sending simple IDENTIFY command to the server. */
201 ctx = silc_client_command_alloc();
202 ctx->client = client;
204 ctx->command = silc_client_command_find("IDENTIFY");
205 memset(ident, 0, sizeof(ident));
206 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
207 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
208 &ctx->argv_types, &ctx->argc, 2);
209 ctx->command->cb(ctx);
212 silc_idcache_list_free(list);
219 if (!server && !num) {
220 /* Take first found cache entry */
221 if (!silc_idcache_list_first(list, &id_cache))
224 entry = (SilcClientEntry)id_cache->context;
226 /* Check multiple cache entries for match */
227 silc_idcache_list_first(list, &id_cache);
228 entry = (SilcClientEntry)id_cache->context;
231 if (server && entry->server &&
232 !strncasecmp(server, entry->server, strlen(server)))
235 if (num && entry->num == num)
238 if (!silc_idcache_list_next(list, &id_cache)) {
243 entry = (SilcClientEntry)id_cache->context;
246 /* If match weren't found, request it */
252 silc_idcache_list_free(list);
257 /* Finds entry for client by the client's ID. Returns the entry or NULL
258 if the entry was not found. */
260 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
261 SilcClientConnection conn,
262 SilcClientID *client_id)
264 SilcIDCacheEntry id_cache;
266 SILC_LOG_DEBUG(("Finding client by ID (%s)",
267 silc_id_render(client_id, SILC_ID_CLIENT)));
269 /* Find ID from cache */
270 if (!silc_idcache_find_by_id_one(conn->client_cache, client_id,
271 SILC_ID_CLIENT, &id_cache))
274 SILC_LOG_DEBUG(("Found"));
276 return (SilcClientEntry)id_cache->context;
281 SilcClientConnection conn;
282 SilcClientID *client_id;
283 SilcGetClientCallback completion;
286 } *GetClientByIDInternal;
288 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
290 GetClientByIDInternal i = (GetClientByIDInternal)context;
291 SilcClientEntry entry;
294 entry = silc_client_get_client_by_id(i->client, i->conn,
297 i->completion(i->client, i->conn, &entry, 1, i->context);
302 static void silc_client_get_client_by_id_destructor(void *context)
304 GetClientByIDInternal i = (GetClientByIDInternal)context;
306 if (i->found == FALSE)
307 i->completion(i->client, i->conn, NULL, 0, i->context);
310 silc_free(i->client_id);
314 /* Same as above but will always resolve the information from the server.
315 Use this only if you know that you don't have the entry and the only
316 thing you know about the client is its ID. */
318 void silc_client_get_client_by_id_resolve(SilcClient client,
319 SilcClientConnection conn,
320 SilcClientID *client_id,
321 SilcGetClientCallback completion,
325 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
327 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
328 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
330 1, 3, idp->data, idp->len);
331 silc_buffer_free(idp);
335 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
336 i->completion = completion;
337 i->context = context;
339 /* Add pending callback */
340 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
342 silc_client_get_client_by_id_destructor,
343 silc_client_command_get_client_by_id_callback,
347 /* Finds entry for channel by the channel name. Returns the entry or NULL
348 if the entry was not found. It is found only if the client is joined
351 SilcChannelEntry silc_client_get_channel(SilcClient client,
352 SilcClientConnection conn,
355 SilcIDCacheEntry id_cache;
356 SilcChannelEntry entry;
358 if (!silc_idcache_find_by_data_one(conn->channel_cache, channel, &id_cache))
361 entry = (SilcChannelEntry)id_cache->context;