Moved silc_client_ch[u]mode[_char] to client library from silc/.
[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
152   if (!silc_idcache_add(id_list->clients, client->nickname, SILC_ID_CLIENT,
153                         (void *)client->id, (void *)client, TRUE)) {
154     silc_free(client);
155     return NULL;
156   }
157
158   return client;
159 }
160
161 /* Free client entry. This free's everything and removes the entry
162    from ID cache. */
163
164 void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
165 {
166   if (entry) {
167     /* Remove from cache */
168     if (entry->id)
169       silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT, 
170                              (void *)entry->id);
171
172     /* Free data */
173     if (entry->nickname)
174       silc_free(entry->nickname);
175     if (entry->username)
176       silc_free(entry->username);
177     if (entry->userinfo)
178       silc_free(entry->userinfo);
179     if (entry->id)
180       silc_free(entry->id);
181     if (entry->send_key)
182       silc_cipher_free(entry->send_key);
183     if (entry->receive_key)
184       silc_cipher_free(entry->receive_key);
185     if (entry->pkcs)
186       silc_pkcs_free(entry->pkcs);
187     if (entry->public_key)
188       silc_pkcs_public_key_free(entry->public_key);
189     if (entry->hmac)
190       silc_hmac_free(entry->hmac);
191   }
192 }
193
194 /* Returns all clients matching requested nickname. Number of clients is
195    returned to `clients_count'. Caller must free the returned table. */
196
197 SilcClientEntry *
198 silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
199                                     char *server, unsigned int *clients_count)
200 {
201   SilcIDCacheList list = NULL;
202   SilcIDCacheEntry id_cache = NULL;
203   SilcClientEntry *clients;
204   int i;
205
206   if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
207     return NULL;
208
209   clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
210
211   i = 0;
212   silc_idcache_list_first(list, &id_cache);
213   clients[i++] = (SilcClientEntry)id_cache->context;
214
215   while (silc_idcache_list_next(list, &id_cache))
216     clients[i++] = (SilcClientEntry)id_cache->context;
217   
218   silc_idcache_list_free(list);
219   
220   if (clients_count)
221     *clients_count = i;
222
223   return clients;
224 }
225
226 /* Finds client entry by nickname. */
227
228 SilcClientEntry
229 silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
230                                     char *server)
231 {
232   SilcIDCacheList list = NULL;
233   SilcIDCacheEntry id_cache = NULL;
234   SilcClientEntry client = NULL;
235
236   SILC_LOG_DEBUG(("Finding client by nickname"));
237
238   if (server) {
239     if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
240       return NULL;
241
242 #if 0
243     while (silc_idcache_list_next(list, &id_cache)) {
244       client = (SilcClientEntry)id_cache->context;
245
246       if (!strcmp(server, XXX, strlen(server)))
247         break;
248
249       client = NULL;
250     }
251 #endif
252
253    silc_idcache_list_free(list);
254
255    if (!client)
256      return NULL;
257   } else {
258     if (!silc_idcache_find_by_data_one(id_list->clients, nickname, &id_cache))
259       return NULL;
260
261     client = (SilcClientEntry)id_cache->context;
262   }
263
264   return client;
265 }
266
267 /* Finds client by nickname hash. */
268
269 SilcClientEntry
270 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
271                                 SilcHash md5hash)
272 {
273   SilcIDCacheList list = NULL;
274   SilcIDCacheEntry id_cache = NULL;
275   SilcClientEntry client = NULL;
276   unsigned char hash[32];
277
278   SILC_LOG_DEBUG(("Finding client by hash"));
279
280   silc_hash_make(md5hash, nickname, strlen(nickname), hash);
281
282   if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
283                                SILC_ID_CLIENT, &list))
284     return NULL;
285
286   if (!silc_idcache_list_first(list, &id_cache)) {
287     silc_idcache_list_free(list);
288     return NULL;
289   }
290
291   while (id_cache) {
292     client = (SilcClientEntry)id_cache->context;
293     
294     if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
295       break;
296
297     id_cache = NULL;
298     client = NULL;
299
300     if (!silc_idcache_list_next(list, &id_cache))
301       break;
302   }
303   
304   silc_idcache_list_free(list);
305
306   return client;
307 }
308
309 /* Finds client by Client ID */
310
311 SilcClientEntry
312 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id)
313 {
314   SilcIDCacheEntry id_cache = NULL;
315   SilcClientEntry client;
316
317   if (!id)
318     return NULL;
319
320   SILC_LOG_DEBUG(("Finding client by ID"));
321
322   if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, 
323                                    SILC_ID_CLIENT, &id_cache))
324     return NULL;
325
326   client = (SilcClientEntry)id_cache->context;
327
328   return client;
329 }
330
331 /* Replaces old Client ID with new one */
332
333 SilcClientEntry
334 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
335                               SilcClientID *new_id)
336 {
337   SilcIDCacheEntry id_cache = NULL;
338   SilcClientEntry client;
339
340   if (!old_id || !new_id)
341     return NULL;
342
343   SILC_LOG_DEBUG(("Replacing Client ID"));
344
345   if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id, 
346                                    SILC_ID_CLIENT, &id_cache))
347     return NULL;
348
349   client = (SilcClientEntry)id_cache->context;
350   silc_free(client->id);
351   client->id = new_id;
352   id_cache->id = (void *)new_id;
353
354   return client;
355 }
356
357
358 /******************************************************************************
359
360                           Channel entry functions
361
362 ******************************************************************************/
363
364 /* Add new channel entry. This add the new channel entry to the ID cache
365    system and returns the allocated entry or NULL on error. */
366
367 SilcChannelEntry
368 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
369                         SilcChannelID *id, SilcServerEntry router,
370                         SilcCipher channel_key)
371 {
372   SilcChannelEntry channel;
373
374   channel = silc_calloc(1, sizeof(*channel));
375   channel->channel_name = channel_name;
376   channel->mode = mode;
377   channel->id = id;
378   channel->router = router;
379   channel->channel_key = channel_key;
380   silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct, 
381                  next);
382
383   if (!silc_idcache_add(id_list->channels, channel->channel_name, 
384                         SILC_ID_CHANNEL, (void *)channel->id, 
385                         (void *)channel, TRUE)) {
386     silc_free(channel);
387     return NULL;
388   }
389
390   return channel;
391 }
392
393 /* Free channel entry.  This free's everything. */
394
395 void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
396 {
397   if (entry) {
398     SilcChannelClientEntry chl;
399
400     /* Remove from cache */
401     if (entry->id)
402       silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL, 
403                              (void *)entry->id);
404
405     /* Free data */
406     if (entry->channel_name)
407       silc_free(entry->channel_name);
408     if (entry->id)
409       silc_free(entry->id);
410     if (entry->topic)
411       silc_free(entry->topic);
412     if (entry->channel_key)
413       silc_cipher_free(entry->channel_key);
414     if (entry->key) {
415       memset(entry->key, 0, entry->key_len / 8);
416       silc_free(entry->key);
417     }
418     memset(entry->iv, 0, sizeof(entry->iv));
419     
420     silc_list_start(entry->user_list);
421     while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
422       silc_list_del(entry->user_list, chl);
423       silc_free(chl);
424     }
425   }
426 }
427
428 /* Finds channel by channel name. Channel names are unique and they
429    are not case-sensitive. */
430
431 SilcChannelEntry
432 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name)
433 {
434   SilcIDCacheList list = NULL;
435   SilcIDCacheEntry id_cache = NULL;
436   SilcChannelEntry channel;
437
438   SILC_LOG_DEBUG(("Finding channel by name"));
439
440   if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
441     return NULL;
442   
443   if (!silc_idcache_list_first(list, &id_cache)) {
444     silc_idcache_list_free(list);
445     return NULL;
446   }
447
448   channel = (SilcChannelEntry)id_cache->context;
449
450   silc_idcache_list_free(list);
451
452   return channel;
453 }
454
455 /* Finds channel by Channel ID. */
456
457 SilcChannelEntry
458 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id)
459 {
460   SilcIDCacheEntry id_cache = NULL;
461   SilcChannelEntry channel;
462
463   if (!id)
464     return NULL;
465
466   SILC_LOG_DEBUG(("Finding channel by ID"));
467
468   if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, 
469                                    SILC_ID_CHANNEL, &id_cache))
470     return NULL;
471
472   channel = (SilcChannelEntry)id_cache->context;
473
474   return channel;
475 }