updates.
[silc.git] / apps / silcd / server_util.c
1 /*
2
3   server_util.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 /* Removes the client from channels and possibly removes the channels
25    as well.  After removing those channels that exist, their channel
26    keys are regnerated. This is called only by the function
27    silc_server_remove_clients_by_server. */
28
29 static void silc_server_remove_clients_channels(SilcServer server, 
30                                                 SilcSocketConnection sock,
31                                                 SilcClientEntry client,
32                                                 SilcHashTable channels)
33 {
34   SilcChannelEntry channel;
35   SilcChannelClientEntry chl;
36   SilcHashTableList htl;
37   SilcBuffer clidp;
38
39   SILC_LOG_DEBUG(("Start"));
40
41   if (!client || !client->id)
42     return;
43
44   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
45
46   /* Remove the client from all channels. The client is removed from
47      the channels' user list. */
48   silc_hash_table_list(client->channels, &htl);
49   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
50     channel = chl->channel;
51
52     /* Remove channel from client's channel list */
53     silc_hash_table_del(client->channels, channel);
54
55     /* Remove channel if there is no users anymore */
56     if (server->server_type == SILC_ROUTER &&
57         silc_hash_table_count(channel->user_list) < 2) {
58
59       if (silc_hash_table_find(channels, channel, NULL, NULL))
60         silc_hash_table_del(channels, channel);
61
62       if (channel->rekey)
63         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
64
65       if (silc_idlist_del_channel(server->local_list, channel))
66         server->stat.my_channels--;
67       else 
68         silc_idlist_del_channel(server->global_list, channel);
69       continue;
70     }
71
72     /* Remove client from channel's client list */
73     silc_hash_table_del(channel->user_list, chl->client);
74
75     /* If there is no global users on the channel anymore mark the channel
76        as local channel. Do not check if the removed client is local client. */
77     if (server->server_type != SILC_ROUTER && channel->global_users && 
78         chl->client->router && !silc_server_channel_has_global(channel))
79       channel->global_users = FALSE;
80
81     silc_free(chl);
82     server->stat.my_chanclients--;
83
84     /* If there is not at least one local user on the channel then we don't
85        need the channel entry anymore, we can remove it safely. */
86     if (server->server_type != SILC_ROUTER &&
87         !silc_server_channel_has_local(channel)) {
88
89       if (silc_hash_table_find(channels, channel, NULL, NULL))
90         silc_hash_table_del(channels, channel);
91
92       if (channel->rekey)
93         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
94
95       if (channel->founder_key) {
96         /* The founder auth data exists, do not remove the channel entry */
97         SilcChannelClientEntry chl2;
98         SilcHashTableList htl2;
99
100         channel->disabled = TRUE;
101
102         silc_hash_table_list(channel->user_list, &htl2);
103         while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
104           silc_hash_table_del(chl2->client->channels, channel);
105           silc_hash_table_del(channel->user_list, chl2->client);
106           silc_free(chl2);
107         }
108         continue;
109       }
110
111       /* Remove the channel entry */
112       if (silc_idlist_del_channel(server->local_list, channel))
113         server->stat.my_channels--;
114       else 
115         silc_idlist_del_channel(server->global_list, channel);
116       continue;
117     }
118
119     /* Add the channel to the the channels list to regenerate the 
120        channel key */
121     if (!silc_hash_table_find(channels, channel, NULL, NULL))
122       silc_hash_table_add(channels, channel, channel);
123   }
124
125   silc_buffer_free(clidp);
126 }
127
128 /* This function is used to remove all client entries by the server `entry'.
129    This is called when the connection is lost to the server. In this case
130    we must invalidate all the client entries owned by the server `entry'. 
131    If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
132    distributed to our local clients. */
133
134 bool silc_server_remove_clients_by_server(SilcServer server, 
135                                           SilcServerEntry entry,
136                                           bool server_signoff)
137 {
138   SilcIDCacheList list = NULL;
139   SilcIDCacheEntry id_cache = NULL;
140   SilcClientEntry client = NULL;
141   SilcBuffer idp;
142   SilcClientEntry *clients = NULL;
143   uint32 clients_c = 0;
144   unsigned char **argv = NULL;
145   uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
146   SilcHashTableList htl;
147   SilcChannelEntry channel;
148   SilcHashTable channels;
149   int i;
150
151   SILC_LOG_DEBUG(("Start"));
152
153   /* Allocate the hash table that holds the channels that require
154      channel key re-generation after we've removed this server's clients
155      from the channels. */
156   channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
157                                    NULL, NULL, TRUE);
158
159   if (server_signoff) {
160     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
161     argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
162     argv_lens = silc_realloc(argv_lens,  sizeof(*argv_lens) * (argc + 1));
163     argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
164     argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
165     memcpy(argv[argc], idp->data, idp->len);
166     argv_lens[argc] = idp->len;
167     argv_types[argc] = argc + 1;
168     argc++;
169     silc_buffer_free(idp);
170   }
171
172   if (silc_idcache_get_all(server->local_list->clients, &list)) {
173
174     if (silc_idcache_list_first(list, &id_cache)) {
175       while (id_cache) {
176         client = (SilcClientEntry)id_cache->context;
177         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
178           if (!silc_idcache_list_next(list, &id_cache))
179             break;
180           else
181             continue;
182         }
183
184         if (client->router != entry) {
185           if (server_signoff) {
186             clients = silc_realloc(clients, 
187                                    sizeof(*clients) * (clients_c + 1));
188             clients[clients_c] = client;
189             clients_c++;
190           }
191
192           if (!silc_idcache_list_next(list, &id_cache))
193             break;
194           else
195             continue;
196         }
197
198         if (server_signoff) {
199           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
200           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
201           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
202                                    (argc + 1));
203           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
204                                     (argc + 1));
205           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
206           memcpy(argv[argc], idp->data, idp->len);
207           argv_lens[argc] = idp->len;
208           argv_types[argc] = argc + 1;
209           argc++;
210           silc_buffer_free(idp);
211         }
212
213         /* Update statistics */
214         server->stat.clients--;
215         if (server->server_type == SILC_ROUTER)
216           server->stat.cell_clients--;
217         SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
218         SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
219
220         /* Remove the client entry */
221         silc_server_remove_clients_channels(server, NULL, client, channels);
222         if (!server_signoff) {
223           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
224           id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
225         } else {
226           silc_idlist_del_client(server->local_list, client);
227         }
228
229         if (!silc_idcache_list_next(list, &id_cache))
230           break;
231       }
232     }
233     silc_idcache_list_free(list);
234   }
235   
236   if (silc_idcache_get_all(server->global_list->clients, &list)) {
237
238     if (silc_idcache_list_first(list, &id_cache)) {
239       while (id_cache) {
240         client = (SilcClientEntry)id_cache->context;
241         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
242           if (!silc_idcache_list_next(list, &id_cache))
243             break;
244           else
245             continue;
246         }
247         
248         if (client->router != entry) {
249           if (server_signoff && client->connection) {
250             clients = silc_realloc(clients, 
251                                    sizeof(*clients) * (clients_c + 1));
252             clients[clients_c] = client;
253             clients_c++;
254           }
255
256           if (!silc_idcache_list_next(list, &id_cache))
257             break;
258           else
259             continue;
260         }
261
262         if (server_signoff) {
263           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
264           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
265           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
266                                    (argc + 1));
267           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
268                                     (argc + 1));
269           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
270           memcpy(argv[argc], idp->data, idp->len);
271           argv_lens[argc] = idp->len;
272           argv_types[argc] = argc + 1;
273           argc++;
274           silc_buffer_free(idp);
275         }
276
277         /* Update statistics */
278         server->stat.clients--;
279         if (server->server_type == SILC_ROUTER)
280           server->stat.cell_clients--;
281         SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
282         SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
283
284         /* Remove the client entry */
285         silc_server_remove_clients_channels(server, NULL, client, channels);
286         if (!server_signoff) {
287           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
288           id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
289         } else {
290           silc_idlist_del_client(server->global_list, client);
291         }
292
293         if (!silc_idcache_list_next(list, &id_cache))
294           break;
295       }
296     }
297     silc_idcache_list_free(list);
298   }
299
300   /* Send the SERVER_SIGNOFF notify */
301   if (server_signoff) {
302     SilcBuffer args, not;
303
304     /* Send SERVER_SIGNOFF notify to our primary router */
305     if (!server->standalone && server->router &&
306         server->router != entry) {
307       args = silc_argument_payload_encode(1, argv, argv_lens,
308                                           argv_types);
309       silc_server_send_notify_args(server, 
310                                    server->router->connection,
311                                    server->server_type == SILC_SERVER ? 
312                                    FALSE : TRUE, 
313                                    SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
314                                    argc, args);
315       silc_buffer_free(args);
316     }
317
318     /* Send to local clients. We also send the list of client ID's that
319        is to be removed for those servers that would like to use that list. */
320     args = silc_argument_payload_encode(argc, argv, argv_lens,
321                                         argv_types);
322     not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
323                                           argc, args);
324     silc_server_packet_send_clients(server, clients, clients_c,
325                                     SILC_PACKET_NOTIFY, 0, FALSE,
326                                     not->data, not->len, FALSE);
327
328     silc_free(clients);
329     silc_buffer_free(args);
330     silc_buffer_free(not);
331     for (i = 0; i < argc; i++)
332       silc_free(argv[i]);
333     silc_free(argv);
334     silc_free(argv_lens);
335     silc_free(argv_types);
336   }
337
338   /* We must now re-generate the channel key for all channels that had
339      this server's client(s) on the channel. As they left the channel we
340      must re-generate the channel key. */
341   silc_hash_table_list(channels, &htl);
342   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
343     if (!silc_server_create_channel_key(server, channel, 0))
344       return FALSE;
345
346     /* Do not send the channel key if private channel key mode is set */
347     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
348       continue;
349
350     silc_server_send_channel_key(server, NULL, channel, 
351                                  server->server_type == SILC_ROUTER ? 
352                                  FALSE : !server->standalone);
353   }
354   silc_hash_table_free(channels);
355
356   return TRUE;
357 }
358
359 static SilcServerEntry
360 silc_server_update_clients_by_real_server(SilcServer server,
361                                           SilcServerEntry from,
362                                           SilcClientEntry client,
363                                           bool local,
364                                           SilcIDCacheEntry client_cache)
365 {
366   SilcServerEntry server_entry;
367   SilcIDCacheEntry id_cache = NULL;
368   SilcIDCacheList list;
369
370   if (!silc_idcache_get_all(server->local_list->servers, &list))
371     return NULL;
372
373   if (silc_idcache_list_first(list, &id_cache)) {
374     while (id_cache) {
375       server_entry = (SilcServerEntry)id_cache->context;
376       if (server_entry != from &&
377           SILC_ID_COMPARE(server_entry->id, client->id, 
378                           client->id->ip.data_len)) {
379         SILC_LOG_DEBUG(("Found (local) %s",
380                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
381
382         if (!server_entry->data.send_key && server_entry->router) {
383           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
384           /* If the client is not marked as local then move it to local list
385              since the server is local. */
386           if (!local) {
387             SILC_LOG_DEBUG(("Moving client to local list"));
388             silc_idcache_add(server->local_list->clients, client_cache->name,
389                              client_cache->id, client_cache->context,
390                              client_cache->expire, NULL);
391             silc_idcache_del_by_context(server->global_list->clients, client);
392           }
393           server_entry = server_entry->router;
394         } else {
395           /* If the client is not marked as local then move it to local list
396              since the server is local. */
397           if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
398             SILC_LOG_DEBUG(("Moving client to local list"));
399             silc_idcache_add(server->local_list->clients, client_cache->name,
400                              client_cache->id, client_cache->context,
401                              client_cache->expire, NULL);
402             silc_idcache_del_by_context(server->global_list->clients, client);
403           }
404         }
405
406         silc_idcache_list_free(list);
407         return server_entry;
408       }
409
410       if (!silc_idcache_list_next(list, &id_cache))
411         break;
412     }
413   }
414
415   silc_idcache_list_free(list);
416
417   if (!silc_idcache_get_all(server->global_list->servers, &list))
418     return NULL;
419
420   if (silc_idcache_list_first(list, &id_cache)) {
421     while (id_cache) {
422       server_entry = (SilcServerEntry)id_cache->context;
423       if (server_entry != from &&
424           SILC_ID_COMPARE(server_entry->id, client->id, 
425                           client->id->ip.data_len)) {
426         SILC_LOG_DEBUG(("Found (global) %s",
427                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
428
429         if (!server_entry->data.send_key && server_entry->router) {
430           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
431           /* If the client is marked as local then move it to global list
432              since the server is global. */
433           if (local) {
434             SILC_LOG_DEBUG(("Moving client to global list"));
435             silc_idcache_add(server->global_list->clients, client_cache->name,
436                              client_cache->id, client_cache->context,
437                              client_cache->expire, NULL);
438             silc_idcache_del_by_context(server->local_list->clients, client);
439           }
440           server_entry = server_entry->router;
441         } else {
442           /* If the client is marked as local then move it to global list
443              since the server is global. */
444           if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
445             SILC_LOG_DEBUG(("Moving client to global list"));
446             silc_idcache_add(server->global_list->clients, client_cache->name,
447                              client_cache->id, client_cache->context,
448                              client_cache->expire, NULL);
449             silc_idcache_del_by_context(server->local_list->clients, client);
450           }
451         }
452
453         silc_idcache_list_free(list);
454         return server_entry;
455       }
456
457       if (!silc_idcache_list_next(list, &id_cache))
458         break;
459     }
460   }
461
462   silc_idcache_list_free(list);
463
464   return NULL;
465 }
466
467 /* Updates the clients that are originated from the `from' to be originated
468    from the `to'. If the `resolve_real_server' is TRUE then this will
469    attempt to figure out which clients really are originated from the
470    `from' and which are originated from a server that we have connection
471    to, when we've acting as backup router. If it is FALSE the `to' will
472    be the new source. This function also removes the clients that are
473    *really* originated from `from' if `remove_from' is TRUE. These are
474    clients that the `from' owns, and not just clients that are behind
475    the `from'. */
476
477 void silc_server_update_clients_by_server(SilcServer server, 
478                                           SilcServerEntry from,
479                                           SilcServerEntry to,
480                                           bool resolve_real_server,
481                                           bool remove_from)
482 {
483   SilcIDCacheList list = NULL;
484   SilcIDCacheEntry id_cache = NULL;
485   SilcClientEntry client = NULL;
486   bool local;
487
488   SILC_LOG_DEBUG(("Start"));
489
490   SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
491                                                 SILC_ID_SERVER)));
492   SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
493                                           SILC_ID_SERVER)));
494
495
496   local = FALSE;
497   if (silc_idcache_get_all(server->global_list->clients, &list)) {
498     if (silc_idcache_list_first(list, &id_cache)) {
499       while (id_cache) {
500         client = (SilcClientEntry)id_cache->context;
501         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
502           if (!silc_idcache_list_next(list, &id_cache))
503             break;
504           else
505             continue;
506         }
507
508         SILC_LOG_DEBUG(("Client (global) %s", 
509                         silc_id_render(client->id, SILC_ID_CLIENT)));
510         if (client->router)
511           SILC_LOG_DEBUG(("Client->router (global) %s", 
512                           silc_id_render(client->router->id, SILC_ID_SERVER)));
513
514         if (client->router == from) {
515           /* Skip clients that are *really* owned by the `from' */
516           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
517                                              client->id->ip.data_len)) {
518             SILC_LOG_DEBUG(("Found really owned client, skip it"));
519             if (!silc_idcache_list_next(list, &id_cache))
520               break;
521             else
522               continue;
523           }
524
525           if (resolve_real_server) {
526             client->router = 
527               silc_server_update_clients_by_real_server(server, from, client,
528                                                         local, id_cache);
529             if (!client->router)
530               client->router = to;
531           } else {
532             client->router = to;
533           }
534         }
535
536         if (!silc_idcache_list_next(list, &id_cache))
537           break;
538       }
539     }
540     silc_idcache_list_free(list);
541   }
542
543   local = TRUE;
544   if (silc_idcache_get_all(server->local_list->clients, &list)) {
545     if (silc_idcache_list_first(list, &id_cache)) {
546       while (id_cache) {
547         client = (SilcClientEntry)id_cache->context;
548         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
549           if (!silc_idcache_list_next(list, &id_cache))
550             break;
551           else
552             continue;
553         }
554
555         SILC_LOG_DEBUG(("Client (local) %s", 
556                         silc_id_render(client->id, SILC_ID_CLIENT)));
557         if (client->router)
558           SILC_LOG_DEBUG(("Client->router (local) %s", 
559                           silc_id_render(client->router->id, SILC_ID_SERVER)));
560
561         if (client->router == from) {
562           /* Skip clients that are *really* owned by the `from' */
563           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
564                                              client->id->ip.data_len)) {
565             SILC_LOG_DEBUG(("Found really owned client, skip it"));
566             if (!silc_idcache_list_next(list, &id_cache))
567               break;
568             else
569               continue;
570           }
571
572           if (resolve_real_server) {
573             client->router = 
574               silc_server_update_clients_by_real_server(server, from, client,
575                                                         local, id_cache);
576             if (!client->router)
577               client->router = from; /* on local list put old from */
578           } else {
579             client->router = to;
580           }
581         }
582
583         if (!silc_idcache_list_next(list, &id_cache))
584           break;
585       }
586     }
587     silc_idcache_list_free(list);
588   }
589
590   if (remove_from)
591     /* Now remove the clients that are still marked as orignated from the
592        `from'. These are the clients that really was owned by the `from' and
593        not just exist behind the `from'. */
594     silc_server_remove_clients_by_server(server, from, TRUE);
595 }
596
597 /* Updates servers that are from `from' to be originated from `to'.  This
598    will also update the server's connection to `to's connection. */
599
600 void silc_server_update_servers_by_server(SilcServer server, 
601                                           SilcServerEntry from,
602                                           SilcServerEntry to)
603 {
604   SilcIDCacheList list = NULL;
605   SilcIDCacheEntry id_cache = NULL;
606   SilcServerEntry server_entry = NULL;
607
608   SILC_LOG_DEBUG(("Start"));
609
610   if (silc_idcache_get_all(server->local_list->servers, &list)) {
611     if (silc_idcache_list_first(list, &id_cache)) {
612       while (id_cache) {
613         server_entry = (SilcServerEntry)id_cache->context;
614         if (server_entry->router == from) {
615           server_entry->router = to;
616           server_entry->connection = to->connection;
617         }
618         if (!silc_idcache_list_next(list, &id_cache))
619           break;
620       }
621     }
622     silc_idcache_list_free(list);
623   }
624
625   if (silc_idcache_get_all(server->global_list->servers, &list)) {
626     if (silc_idcache_list_first(list, &id_cache)) {
627       while (id_cache) {
628         server_entry = (SilcServerEntry)id_cache->context;
629         if (server_entry->router == from) {
630           server_entry->router = to;
631           server_entry->connection = to->connection;
632         }
633         if (!silc_idcache_list_next(list, &id_cache))
634           break;
635       }
636     }
637     silc_idcache_list_free(list);
638   }
639 }
640
641 /* Removes channels that are from `from. */
642
643 void silc_server_remove_channels_by_server(SilcServer server, 
644                                            SilcServerEntry from)
645 {
646   SilcIDCacheList list = NULL;
647   SilcIDCacheEntry id_cache = NULL;
648   SilcChannelEntry channel = NULL;
649
650   SILC_LOG_DEBUG(("Start"));
651
652   if (silc_idcache_get_all(server->global_list->channels, &list)) {
653     if (silc_idcache_list_first(list, &id_cache)) {
654       while (id_cache) {
655         channel = (SilcChannelEntry)id_cache->context;
656         if (channel->router == from)
657           silc_idlist_del_channel(server->global_list, channel);
658         if (!silc_idcache_list_next(list, &id_cache))
659           break;
660       }
661     }
662     silc_idcache_list_free(list);
663   }
664 }
665
666 /* Updates channels that are from `from' to be originated from `to'.  */
667
668 void silc_server_update_channels_by_server(SilcServer server, 
669                                            SilcServerEntry from,
670                                            SilcServerEntry to)
671 {
672   SilcIDCacheList list = NULL;
673   SilcIDCacheEntry id_cache = NULL;
674   SilcChannelEntry channel = NULL;
675
676   SILC_LOG_DEBUG(("Start"));
677
678   if (silc_idcache_get_all(server->global_list->channels, &list)) {
679     if (silc_idcache_list_first(list, &id_cache)) {
680       while (id_cache) {
681         channel = (SilcChannelEntry)id_cache->context;
682         if (channel->router == from)
683           channel->router = to;
684         if (!silc_idcache_list_next(list, &id_cache))
685           break;
686       }
687     }
688     silc_idcache_list_free(list);
689   }
690 }
691
692 /* Checks whether given channel has global users.  If it does this returns
693    TRUE and FALSE if there is only locally connected clients on the channel. */
694
695 bool silc_server_channel_has_global(SilcChannelEntry channel)
696 {
697   SilcChannelClientEntry chl;
698   SilcHashTableList htl;
699
700   silc_hash_table_list(channel->user_list, &htl);
701   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
702     if (chl->client->router)
703       return TRUE;
704   }
705
706   return FALSE;
707 }
708
709 /* Checks whether given channel has locally connected users.  If it does this
710    returns TRUE and FALSE if there is not one locally connected client. */
711
712 bool silc_server_channel_has_local(SilcChannelEntry channel)
713 {
714   SilcChannelClientEntry chl;
715   SilcHashTableList htl;
716
717   silc_hash_table_list(channel->user_list, &htl);
718   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
719     if (!chl->client->router)
720       return TRUE;
721   }
722
723   return FALSE;
724 }
725
726 /* Returns TRUE if the given client is on the channel.  FALSE if not. 
727    This works because we assure that the user list on the channel is
728    always in up to date thus we can only check the channel list from 
729    `client' which is faster than checking the user list from `channel'. */
730
731 bool silc_server_client_on_channel(SilcClientEntry client,
732                                    SilcChannelEntry channel)
733 {
734   if (!client || !channel)
735     return FALSE;
736
737   if (silc_hash_table_find(client->channels, channel, NULL, NULL))
738     return TRUE;
739
740   return FALSE;
741 }
742
743 /* Checks string for bad characters and returns TRUE if they are found. */
744
745 bool silc_server_name_bad_chars(const char *name, uint32 name_len)
746 {
747   int i;
748
749   for (i = 0; i < name_len; i++) {
750     if (!isascii(name[i]))
751       return TRUE;
752     if (name[i] <= 32) return TRUE;
753     if (name[i] == ' ') return TRUE;
754     if (name[i] == '*') return TRUE;
755     if (name[i] == '?') return TRUE;
756     if (name[i] == ',') return TRUE;
757   }
758
759   return FALSE;
760 }
761
762 /* Modifies the `name' if it includes bad characters and returns new
763    allocated name that does not include bad characters. */
764
765 char *silc_server_name_modify_bad(const char *name, uint32 name_len)
766 {
767   int i;
768   char *newname = strdup(name);
769
770   for (i = 0; i < name_len; i++) {
771     if (!isascii(newname[i])) newname[i] = '_';
772     if (newname[i] <= 32) newname[i] = '_';
773     if (newname[i] == ' ') newname[i] = '_';
774     if (newname[i] == '*') newname[i] = '_';
775     if (newname[i] == '?') newname[i] = '_';
776     if (newname[i] == ',') newname[i] = '_';
777   }
778
779   return newname;
780 }