Some bugfixes.
[silc.git] / apps / silcd / idlist.c
1 /*
2
3   idlist.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 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 "serverincludes.h"
23 #include "idlist.h"
24
25 /******************************************************************************
26
27                           Server entry functions
28
29 ******************************************************************************/
30
31 /* Add new server entry. This adds the new server entry to ID cache and
32    returns the allocated entry object or NULL on error. This is called
33    when new server connects to us. We also add ourselves to cache with
34    this function. */
35
36 SilcServerEntry 
37 silc_idlist_add_server(SilcIDList id_list, 
38                        char *server_name, int server_type,
39                        SilcServerID *id, SilcServerEntry router,
40                        SilcCipher send_key, SilcCipher receive_key,
41                        SilcPKCS pkcs, SilcHmac hmac, 
42                        SilcPublicKey public_key, void *connection)
43 {
44   SilcServerEntry server;
45
46   SILC_LOG_DEBUG(("Adding new server entry"));
47
48   server = silc_calloc(1, sizeof(*server));
49   server->server_name = server_name;
50   server->server_type = server_type;
51   server->id = id;
52   server->router = router;
53   server->send_key = send_key;
54   server->receive_key = receive_key;
55   server->pkcs = pkcs;
56   server->hmac = hmac;
57   server->public_key = public_key;
58   server->connection = connection;
59
60   if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
61                         (void *)server->id, (void *)server, TRUE)) {
62     silc_free(server);
63     return NULL;
64   }
65
66   return server;
67 }
68
69 /* Finds server by Server ID */
70
71 SilcServerEntry
72 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id)
73 {
74   SilcIDCacheEntry id_cache = NULL;
75   SilcServerEntry server;
76
77   if (!id)
78     return NULL;
79
80   SILC_LOG_DEBUG(("Finding server by ID"));
81
82   if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, 
83                                    SILC_ID_SERVER, &id_cache))
84     return NULL;
85
86   server = (SilcServerEntry)id_cache->context;
87
88   return server;
89 }
90
91 /* Replaces old Server ID with new one */ 
92
93 SilcServerEntry
94 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
95                               SilcServerID *new_id)
96 {
97   SilcIDCacheEntry id_cache = NULL;
98   SilcServerEntry server;
99
100   if (!old_id || !new_id)
101     return NULL;
102
103   SILC_LOG_DEBUG(("Replacing Server ID"));
104
105   if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, 
106                                    SILC_ID_SERVER, &id_cache))
107     return NULL;
108
109   server = (SilcServerEntry)id_cache->context;
110   silc_free(server->id);
111   server->id = new_id;
112   id_cache->id = (void *)new_id;
113
114   return server;
115 }
116
117 /******************************************************************************
118
119                           Client entry functions
120
121 ******************************************************************************/
122
123 /* Add new client entry. This adds the client entry to ID cache system
124    and returns the allocated client entry or NULL on error.  This is
125    called when new client connection is accepted to the server. */
126
127 SilcClientEntry
128 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
129                        char *userinfo, SilcClientID *id, 
130                        SilcServerEntry router,
131                        SilcCipher send_key, SilcCipher receive_key,
132                        SilcPKCS pkcs, SilcHmac hmac, 
133                        SilcPublicKey public_key, void *connection)
134 {
135   SilcClientEntry client;
136
137   SILC_LOG_DEBUG(("Adding new client entry"));
138
139   client = silc_calloc(1, sizeof(*client));
140   client->nickname = nickname;
141   client->username = username;
142   client->userinfo = userinfo;
143   client->id = id;
144   client->router = router;
145   client->send_key = send_key;
146   client->receive_key = receive_key;
147   client->pkcs = pkcs;
148   client->hmac = hmac;
149   client->public_key = public_key;
150   client->connection = connection;
151   silc_list_init(client->channels, struct SilcChannelClientEntryStruct, 
152                  client_list);
153
154   if (!silc_idcache_add(id_list->clients, client->nickname, SILC_ID_CLIENT,
155                         (void *)client->id, (void *)client, TRUE)) {
156     silc_free(client);
157     return NULL;
158   }
159
160   return client;
161 }
162
163 /* Free client entry. This free's everything and removes the entry
164    from ID cache. */
165
166 void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
167 {
168   if (entry) {
169     /* Remove from cache */
170     if (entry->id)
171       silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT, 
172                              (void *)entry->id);
173
174     /* Free data */
175     if (entry->nickname)
176       silc_free(entry->nickname);
177     if (entry->username)
178       silc_free(entry->username);
179     if (entry->userinfo)
180       silc_free(entry->userinfo);
181     if (entry->id)
182       silc_free(entry->id);
183     if (entry->send_key)
184       silc_cipher_free(entry->send_key);
185     if (entry->receive_key)
186       silc_cipher_free(entry->receive_key);
187     if (entry->pkcs)
188       silc_pkcs_free(entry->pkcs);
189     if (entry->public_key)
190       silc_pkcs_public_key_free(entry->public_key);
191     if (entry->hmac)
192       silc_hmac_free(entry->hmac);
193   }
194 }
195
196 /* Returns all clients matching requested nickname. Number of clients is
197    returned to `clients_count'. Caller must free the returned table. */
198
199 SilcClientEntry *
200 silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
201                                     char *server, unsigned int *clients_count)
202 {
203   SilcIDCacheList list = NULL;
204   SilcIDCacheEntry id_cache = NULL;
205   SilcClientEntry *clients;
206   int i;
207
208   if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
209     return NULL;
210
211   clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
212
213   i = 0;
214   silc_idcache_list_first(list, &id_cache);
215   clients[i++] = (SilcClientEntry)id_cache->context;
216
217   while (silc_idcache_list_next(list, &id_cache))
218     clients[i++] = (SilcClientEntry)id_cache->context;
219   
220   silc_idcache_list_free(list);
221   
222   if (clients_count)
223     *clients_count = i;
224
225   return clients;
226 }
227
228 /* Finds client entry by nickname. */
229
230 SilcClientEntry
231 silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
232                                     char *server)
233 {
234   SilcIDCacheList list = NULL;
235   SilcIDCacheEntry id_cache = NULL;
236   SilcClientEntry client = NULL;
237
238   SILC_LOG_DEBUG(("Finding client by nickname"));
239
240   if (server) {
241     if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
242       return NULL;
243
244 #if 0
245     while (silc_idcache_list_next(list, &id_cache)) {
246       client = (SilcClientEntry)id_cache->context;
247
248       if (!strcmp(server, XXX, strlen(server)))
249         break;
250
251       client = NULL;
252     }
253 #endif
254
255    silc_idcache_list_free(list);
256
257    if (!client)
258      return NULL;
259   } else {
260     if (!silc_idcache_find_by_data_one(id_list->clients, nickname, &id_cache))
261       return NULL;
262
263     client = (SilcClientEntry)id_cache->context;
264   }
265
266   return client;
267 }
268
269 /* Finds client by nickname hash. */
270
271 SilcClientEntry
272 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
273                                 SilcHash md5hash)
274 {
275   SilcIDCacheList list = NULL;
276   SilcIDCacheEntry id_cache = NULL;
277   SilcClientEntry client = NULL;
278   unsigned char hash[32];
279
280   SILC_LOG_DEBUG(("Finding client by hash"));
281
282   silc_hash_make(md5hash, nickname, strlen(nickname), hash);
283
284   if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
285                                SILC_ID_CLIENT, &list))
286     return NULL;
287
288   if (!silc_idcache_list_first(list, &id_cache)) {
289     silc_idcache_list_free(list);
290     return NULL;
291   }
292
293   while (id_cache) {
294     client = (SilcClientEntry)id_cache->context;
295     
296     if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
297       break;
298
299     id_cache = NULL;
300     client = NULL;
301
302     if (!silc_idcache_list_next(list, &id_cache))
303       break;
304   }
305   
306   silc_idcache_list_free(list);
307
308   return client;
309 }
310
311 /* Finds client by Client ID */
312
313 SilcClientEntry
314 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id)
315 {
316   SilcIDCacheEntry id_cache = NULL;
317   SilcClientEntry client;
318
319   if (!id)
320     return NULL;
321
322   SILC_LOG_DEBUG(("Finding client by ID"));
323
324   if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, 
325                                    SILC_ID_CLIENT, &id_cache))
326     return NULL;
327
328   client = (SilcClientEntry)id_cache->context;
329
330   return client;
331 }
332
333 /* Replaces old Client ID with new one */
334
335 SilcClientEntry
336 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
337                               SilcClientID *new_id)
338 {
339   SilcIDCacheEntry id_cache = NULL;
340   SilcClientEntry client;
341
342   if (!old_id || !new_id)
343     return NULL;
344
345   SILC_LOG_DEBUG(("Replacing Client ID"));
346
347   if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id, 
348                                    SILC_ID_CLIENT, &id_cache))
349     return NULL;
350
351   client = (SilcClientEntry)id_cache->context;
352   silc_free(client->id);
353   client->id = new_id;
354   id_cache->id = (void *)new_id;
355
356   return client;
357 }
358
359
360 /******************************************************************************
361
362                           Channel entry functions
363
364 ******************************************************************************/
365
366 /* Add new channel entry. This add the new channel entry to the ID cache
367    system and returns the allocated entry or NULL on error. */
368
369 SilcChannelEntry
370 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
371                         SilcChannelID *id, SilcServerEntry router,
372                         SilcCipher channel_key)
373 {
374   SilcChannelEntry channel;
375
376   channel = silc_calloc(1, sizeof(*channel));
377   channel->channel_name = channel_name;
378   channel->mode = mode;
379   channel->id = id;
380   channel->router = router;
381   channel->channel_key = channel_key;
382   silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct, 
383                  channel_list);
384
385   if (!silc_idcache_add(id_list->channels, channel->channel_name, 
386                         SILC_ID_CHANNEL, (void *)channel->id, 
387                         (void *)channel, TRUE)) {
388     silc_free(channel);
389     return NULL;
390   }
391
392   return channel;
393 }
394
395 /* Free channel entry.  This free's everything. */
396
397 void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
398 {
399   if (entry) {
400     SilcChannelClientEntry chl;
401
402     /* Remove from cache */
403     if (entry->id)
404       silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL, 
405                              (void *)entry->id);
406
407     /* Free data */
408     if (entry->channel_name)
409       silc_free(entry->channel_name);
410     if (entry->id)
411       silc_free(entry->id);
412     if (entry->topic)
413       silc_free(entry->topic);
414     if (entry->channel_key)
415       silc_cipher_free(entry->channel_key);
416     if (entry->key) {
417       memset(entry->key, 0, entry->key_len / 8);
418       silc_free(entry->key);
419     }
420     memset(entry->iv, 0, sizeof(entry->iv));
421     
422     silc_list_start(entry->user_list);
423     while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
424       silc_list_del(entry->user_list, chl);
425       silc_free(chl);
426     }
427   }
428 }
429
430 /* Finds channel by channel name. Channel names are unique and they
431    are not case-sensitive. */
432
433 SilcChannelEntry
434 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name)
435 {
436   SilcIDCacheList list = NULL;
437   SilcIDCacheEntry id_cache = NULL;
438   SilcChannelEntry channel;
439
440   SILC_LOG_DEBUG(("Finding channel by name"));
441
442   if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
443     return NULL;
444   
445   if (!silc_idcache_list_first(list, &id_cache)) {
446     silc_idcache_list_free(list);
447     return NULL;
448   }
449
450   channel = (SilcChannelEntry)id_cache->context;
451
452   silc_idcache_list_free(list);
453
454   return channel;
455 }
456
457 /* Finds channel by Channel ID. */
458
459 SilcChannelEntry
460 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id)
461 {
462   SilcIDCacheEntry id_cache = NULL;
463   SilcChannelEntry channel;
464
465   if (!id)
466     return NULL;
467
468   SILC_LOG_DEBUG(("Finding channel by ID"));
469
470   if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, 
471                                    SILC_ID_CHANNEL, &id_cache))
472     return NULL;
473
474   channel = (SilcChannelEntry)id_cache->context;
475
476   return channel;
477 }