updates.
[silc.git] / lib / silcclient / idlist.c
1 /*
2
3   idlist.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "clientlibincludes.h"
23
24 typedef struct {
25   SilcClientCommandContext cmd;
26   SilcGetClientCallback completion;
27   char *nickname;
28   char *server;
29   void *context;
30   int found;
31 } *GetClientInternal;
32
33 SILC_CLIENT_CMD_FUNC(get_client_callback)
34 {
35   GetClientInternal i = (GetClientInternal)context;
36   SilcClientEntry *clients;
37   unsigned int clients_count;
38
39   /* Get the clients */
40   clients = silc_client_get_clients_local(i->cmd->client, i->cmd->conn,
41                                           i->nickname, i->server,
42                                           &clients_count);
43   if (clients) {
44     i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
45     i->found = TRUE;
46     silc_free(clients);
47   }
48 }
49
50 static void silc_client_get_client_destructor(void *context)
51 {
52   GetClientInternal i = (GetClientInternal)context;
53
54   if (i->found == FALSE)
55     i->completion(i->cmd->client, i->cmd->conn, NULL, 0, i->context);
56
57   silc_client_command_free(i->cmd);
58   if (i->nickname)
59     silc_free(i->nickname);
60   if (i->server)
61     silc_free(i->server);
62   silc_free(i);
63 }
64
65 /* Finds client entry or entries by the `nickname' and `server'. The 
66    completion callback will be called when the client entries has been found.
67
68    Note: this function is always asynchronous and resolves the client
69    information from the server. Thus, if you already know the client
70    information then use the silc_client_get_client_by_id function to
71    get the client entry since this function may be very slow and should
72    be used only to initially get the client entries. */
73
74 void silc_client_get_clients(SilcClient client,
75                              SilcClientConnection conn,
76                              char *nickname,
77                              char *server,
78                              SilcGetClientCallback completion,
79                              void *context)
80 {
81   char ident[512];
82   SilcClientCommandContext ctx;
83   GetClientInternal i = silc_calloc(1, sizeof(*i));
84       
85   /* No ID found. Do query from the server. The query is done by 
86      sending simple IDENTIFY command to the server. */
87   ctx = silc_client_command_alloc();
88   ctx->client = client;
89   ctx->conn = conn;
90   ctx->command = silc_client_command_find("IDENTIFY");
91   memset(ident, 0, sizeof(ident));
92   snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
93   silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
94                           &ctx->argv_types, &ctx->argc, 2);
95   ctx->command->cb(ctx);
96       
97   i->cmd = ctx;
98   i->nickname = nickname ? strdup(nickname) : NULL;
99   i->server = server ? strdup(server) : NULL;
100   i->completion = completion;
101   i->context = context;
102
103   /* Add pending callback */
104   silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
105                               ++conn->cmd_ident, 
106                               silc_client_get_client_destructor,
107                               silc_client_command_get_client_callback, 
108                               (void *)i);
109 }
110
111 /* Same as above function but does not resolve anything from the server.
112    This checks local cache and returns all clients from the cache. */
113
114 SilcClientEntry *silc_client_get_clients_local(SilcClient client,
115                                                SilcClientConnection conn,
116                                                char *nickname,
117                                                char *server,
118                                                unsigned int *clients_count)
119 {
120   SilcIDCacheEntry id_cache;
121   SilcIDCacheList list = NULL;
122   SilcClientEntry entry, *clients;
123   int i = 0;
124
125   /* Find ID from cache */
126   if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list))
127     return NULL;
128
129   if (silc_idcache_list_count(list) == 0)
130     return NULL;
131
132   clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
133   *clients_count = silc_idcache_list_count(list);
134
135   if (!server) {
136     /* Take all without any further checking */
137     silc_idcache_list_first(list, &id_cache);
138     while (id_cache) {
139       clients[i++] = id_cache->context;
140       if (!silc_idcache_list_next(list, &id_cache))
141         break;
142     }
143   } else {
144     /* Check multiple cache entries for match */
145     silc_idcache_list_first(list, &id_cache);
146     while (id_cache) {
147       entry = (SilcClientEntry)id_cache->context;
148       
149       if (entry->server && 
150           strncasecmp(server, entry->server, strlen(server))) {
151         if (!silc_idcache_list_next(list, &id_cache)) {
152           break;
153         } else {
154           continue;
155         }
156       }
157       
158       clients[i++] = id_cache->context;
159       if (!silc_idcache_list_next(list, &id_cache))
160         break;
161     }
162   }
163
164   if (list)
165     silc_idcache_list_free(list);
166
167   return clients;
168 }
169
170 /* The old style function to find client entry. This is used by the
171    library internally. If `query' is TRUE then the client information is
172    requested by the server. The pending command callback must be set
173    by the caller. */
174
175 SilcClientEntry silc_idlist_get_client(SilcClient client,
176                                        SilcClientConnection conn,
177                                        char *nickname,
178                                        char *server,
179                                        unsigned int num,
180                                        int query)
181 {
182   SilcIDCacheEntry id_cache;
183   SilcIDCacheList list = NULL;
184   SilcClientEntry entry = NULL;
185
186   /* Find ID from cache */
187   if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
188   identify:
189
190     if (query) {
191       char ident[512];
192       SilcClientCommandContext ctx;
193       
194       SILC_LOG_DEBUG(("Requesting Client ID from server"));
195       
196       /* No ID found. Do query from the server. The query is done by 
197          sending simple IDENTIFY command to the server. */
198       ctx = silc_client_command_alloc();
199       ctx->client = client;
200       ctx->conn = conn;
201       ctx->command = silc_client_command_find("IDENTIFY");
202       memset(ident, 0, sizeof(ident));
203       snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
204       silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
205                               &ctx->argv_types, &ctx->argc, 2);
206       ctx->command->cb(ctx);
207       
208       if (list)
209         silc_idcache_list_free(list);
210
211       return NULL;
212     }
213     return NULL;
214   }
215
216   if (!server && !num) {
217     /* Take first found cache entry */
218     if (!silc_idcache_list_first(list, &id_cache))
219       goto identify;
220
221     entry = (SilcClientEntry)id_cache->context;
222   } else {
223     /* Check multiple cache entries for match */
224     silc_idcache_list_first(list, &id_cache);
225     entry = (SilcClientEntry)id_cache->context;
226     
227     while (entry) {
228       if (server && entry->server && 
229           !strncasecmp(server, entry->server, strlen(server)))
230         break;
231       
232       if (num && entry->num == num)
233         break;
234
235       if (!silc_idcache_list_next(list, &id_cache)) {
236         entry = NULL;
237         break;
238       }
239
240       entry = (SilcClientEntry)id_cache->context;
241     }
242
243     /* If match weren't found, request it */
244     if (!entry)
245       goto identify;
246   }
247
248   if (list)
249     silc_idcache_list_free(list);
250
251   return entry;
252 }
253
254 /* Finds entry for client by the client's ID. Returns the entry or NULL
255    if the entry was not found. */
256
257 SilcClientEntry silc_client_get_client_by_id(SilcClient client,
258                                              SilcClientConnection conn,
259                                              SilcClientID *client_id)
260 {
261   SilcIDCacheEntry id_cache;
262
263   SILC_LOG_DEBUG(("Finding client by ID (%s)", 
264                   silc_id_render(client_id, SILC_ID_CLIENT)));
265
266   /* Find ID from cache */
267   if (!silc_idcache_find_by_id_one(conn->client_cache, client_id, 
268                                    SILC_ID_CLIENT, &id_cache))
269     return NULL;
270
271   SILC_LOG_DEBUG(("Found"));
272
273   return (SilcClientEntry)id_cache->context;
274 }
275
276 /* Finds entry for channel by the channel name. Returns the entry or NULL
277    if the entry was not found. It is found only if the client is joined
278    to the channel. */
279
280 SilcChannelEntry silc_client_get_channel(SilcClient client,
281                                          SilcClientConnection conn,
282                                          char *channel)
283 {
284   SilcIDCacheEntry id_cache;
285   SilcChannelEntry entry;
286
287   if (!silc_idcache_find_by_data_one(conn->channel_cache, channel, &id_cache))
288     return NULL;
289
290   entry = (SilcChannelEntry)id_cache->context;
291
292   return entry;
293 }