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