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);
175 SilcClientConnection conn;
176 unsigned int list_count;
177 SilcBuffer client_id_list;
178 SilcGetClientCallback completion;
181 } *GetClientsByListInternal;
183 SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
185 GetClientsByListInternal i = (GetClientsByListInternal)context;
186 SilcIDCacheEntry id_cache = NULL;
187 SilcBuffer client_id_list = i->client_id_list;
188 SilcClientEntry *clients = NULL;
189 unsigned int clients_count = 0;
192 for (c = 0; c < i->list_count; c++) {
193 unsigned short idp_len;
194 SilcClientID *client_id;
197 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
199 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
203 /* Get the client entry */
204 if (silc_idcache_find_by_id_one(i->conn->client_cache, (void *)client_id,
205 SILC_ID_CLIENT, &id_cache)) {
206 clients = silc_realloc(clients, sizeof(*clients) *
207 (clients_count + 1));
208 clients[clients_count] = (SilcClientEntry)id_cache->context;
213 silc_free(client_id);
214 silc_buffer_pull(client_id_list, idp_len);
218 i->completion(i->client, i->conn, clients, clients_count, i->context);
223 static void silc_client_get_clients_list_destructor(void *context)
225 GetClientsByListInternal i = (GetClientsByListInternal)context;
227 if (i->found == FALSE)
228 i->completion(i->client, i->conn, NULL, 0, i->context);
230 if (i->client_id_list)
231 silc_buffer_free(i->client_id_list);
235 /* Gets client entries by the list of client ID's `client_id_list'. This
236 always resolves those client ID's it does not know yet from the server
237 so this function might take a while. The `client_id_list' is a list
238 of ID Payloads added one after other. JOIN command reply and USERS
239 command reply for example returns this sort of list. The `completion'
240 will be called after the entries are available. */
242 void silc_client_get_clients_by_list(SilcClient client,
243 SilcClientConnection conn,
244 unsigned int list_count,
245 SilcBuffer client_id_list,
246 SilcGetClientCallback completion,
249 SilcIDCacheEntry id_cache = NULL;
251 unsigned char **res_argv = NULL;
252 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
253 GetClientsByListInternal in;
255 in = silc_calloc(1, sizeof(*in));
258 in->list_count = list_count;
259 in->client_id_list = silc_buffer_copy(client_id_list);
260 in->completion = completion;
261 in->context = context;
263 for (i = 0; i < list_count; i++) {
264 unsigned short idp_len;
265 SilcClientID *client_id;
266 SilcClientEntry entry;
269 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
271 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
275 /* Check if we have this client cached already. */
277 silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
278 SILC_ID_CLIENT, &id_cache);
280 /* If we don't have the entry or it has incomplete info, then resolve
281 it from the server. */
282 entry = id_cache ? (SilcClientEntry)id_cache->context : NULL;
283 if (!id_cache || !entry->nickname) {
284 /* No we don't have it, query it from the server. Assemble argument
285 table that will be sent fr the IDENTIFY command later. */
286 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
288 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
290 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
292 res_argv[res_argc] = client_id_list->data;
293 res_argv_lens[res_argc] = idp_len;
294 res_argv_types[res_argc] = res_argc + 3;
298 silc_free(client_id);
299 silc_buffer_pull(client_id_list, idp_len);
302 /* Query the client information from server if the list included clients
303 that we don't know about. */
307 /* Send the IDENTIFY command to server */
308 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
309 res_argc, res_argv, res_argv_lens,
310 res_argv_types, ++conn->cmd_ident);
311 silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
312 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
315 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
317 silc_client_get_clients_list_destructor,
318 silc_client_command_get_clients_list_callback,
321 silc_buffer_push(client_id_list, client_id_list->data -
322 client_id_list->head);
323 silc_buffer_free(res_cmd);
325 silc_free(res_argv_lens);
326 silc_free(res_argv_types);
330 silc_buffer_push(client_id_list, client_id_list->data -
331 client_id_list->head);
333 /* We have the clients in cache, get them and call the completion */
334 silc_client_command_get_clients_list_callback((void *)in);
337 /* The old style function to find client entry. This is used by the
338 library internally. If `query' is TRUE then the client information is
339 requested by the server. The pending command callback must be set
342 SilcClientEntry silc_idlist_get_client(SilcClient client,
343 SilcClientConnection conn,
349 SilcIDCacheEntry id_cache;
350 SilcIDCacheList list = NULL;
351 SilcClientEntry entry = NULL;
353 /* Find ID from cache */
354 if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
359 SilcClientCommandContext ctx;
361 SILC_LOG_DEBUG(("Requesting Client ID from server"));
363 /* No ID found. Do query from the server. The query is done by
364 sending simple IDENTIFY command to the server. */
365 ctx = silc_client_command_alloc();
366 ctx->client = client;
368 ctx->command = silc_client_command_find("IDENTIFY");
369 memset(ident, 0, sizeof(ident));
370 snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
371 silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens,
372 &ctx->argv_types, &ctx->argc, 2);
373 ctx->command->cb(ctx);
376 silc_idcache_list_free(list);
383 if (!server && !num) {
384 /* Take first found cache entry */
385 if (!silc_idcache_list_first(list, &id_cache))
388 entry = (SilcClientEntry)id_cache->context;
390 /* Check multiple cache entries for match */
391 silc_idcache_list_first(list, &id_cache);
392 entry = (SilcClientEntry)id_cache->context;
395 if (server && entry->server &&
396 !strncasecmp(server, entry->server, strlen(server)))
399 if (num && entry->num == num)
402 if (!silc_idcache_list_next(list, &id_cache)) {
407 entry = (SilcClientEntry)id_cache->context;
410 /* If match weren't found, request it */
416 silc_idcache_list_free(list);
421 /* Finds entry for client by the client's ID. Returns the entry or NULL
422 if the entry was not found. */
424 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
425 SilcClientConnection conn,
426 SilcClientID *client_id)
428 SilcIDCacheEntry id_cache;
430 SILC_LOG_DEBUG(("Finding client by ID (%s)",
431 silc_id_render(client_id, SILC_ID_CLIENT)));
433 /* Find ID from cache */
434 if (!silc_idcache_find_by_id_one(conn->client_cache, client_id,
435 SILC_ID_CLIENT, &id_cache))
438 SILC_LOG_DEBUG(("Found"));
440 return (SilcClientEntry)id_cache->context;
445 SilcClientConnection conn;
446 SilcClientID *client_id;
447 SilcGetClientCallback completion;
450 } *GetClientByIDInternal;
452 SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
454 GetClientByIDInternal i = (GetClientByIDInternal)context;
455 SilcClientEntry entry;
458 entry = silc_client_get_client_by_id(i->client, i->conn,
461 i->completion(i->client, i->conn, &entry, 1, i->context);
466 static void silc_client_get_client_by_id_destructor(void *context)
468 GetClientByIDInternal i = (GetClientByIDInternal)context;
470 if (i->found == FALSE)
471 i->completion(i->client, i->conn, NULL, 0, i->context);
474 silc_free(i->client_id);
478 /* Same as above but will always resolve the information from the server.
479 Use this only if you know that you don't have the entry and the only
480 thing you know about the client is its ID. */
482 void silc_client_get_client_by_id_resolve(SilcClient client,
483 SilcClientConnection conn,
484 SilcClientID *client_id,
485 SilcGetClientCallback completion,
489 GetClientByIDInternal i = silc_calloc(1, sizeof(*i));
491 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
492 silc_client_send_command(client, conn, SILC_COMMAND_WHOIS,
494 1, 3, idp->data, idp->len);
495 silc_buffer_free(idp);
499 i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
500 i->completion = completion;
501 i->context = context;
503 /* Add pending callback */
504 silc_client_command_pending(conn, SILC_COMMAND_WHOIS,
506 silc_client_get_client_by_id_destructor,
507 silc_client_command_get_client_by_id_callback,
511 /* Finds entry for channel by the channel name. Returns the entry or NULL
512 if the entry was not found. It is found only if the client is joined
515 SilcChannelEntry silc_client_get_channel(SilcClient client,
516 SilcClientConnection conn,
519 SilcIDCacheEntry id_cache;
520 SilcChannelEntry entry;
522 if (!silc_idcache_find_by_data_one(conn->channel_cache, channel, &id_cache))
525 entry = (SilcChannelEntry)id_cache->context;