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