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         /* Remove the client entry */
214         silc_server_remove_clients_channels(server, NULL, client, channels);
215         if (!server_signoff) {
216           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
217           id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
218         } else {
219           silc_idlist_del_client(server->local_list, client);
220         }
221         server->stat.clients--;
222         if (server->server_type == SILC_ROUTER)
223           server->stat.cell_clients--;
224
225         if (!silc_idcache_list_next(list, &id_cache))
226           break;
227       }
228     }
229     silc_idcache_list_free(list);
230   }
231   
232   if (silc_idcache_get_all(server->global_list->clients, &list)) {
233
234     if (silc_idcache_list_first(list, &id_cache)) {
235       while (id_cache) {
236         client = (SilcClientEntry)id_cache->context;
237         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
238           if (!silc_idcache_list_next(list, &id_cache))
239             break;
240           else
241             continue;
242         }
243         
244         if (client->router != entry) {
245           if (server_signoff && client->connection) {
246             clients = silc_realloc(clients, 
247                                    sizeof(*clients) * (clients_c + 1));
248             clients[clients_c] = client;
249             clients_c++;
250           }
251
252           if (!silc_idcache_list_next(list, &id_cache))
253             break;
254           else
255             continue;
256         }
257
258         if (server_signoff) {
259           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
260           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
261           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
262                                    (argc + 1));
263           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
264                                     (argc + 1));
265           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
266           memcpy(argv[argc], idp->data, idp->len);
267           argv_lens[argc] = idp->len;
268           argv_types[argc] = argc + 1;
269           argc++;
270           silc_buffer_free(idp);
271         }
272
273         /* Remove the client entry */
274         silc_server_remove_clients_channels(server, NULL, client, channels);
275         if (!server_signoff) {
276           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
277           id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
278         } else {
279           silc_idlist_del_client(server->global_list, client);
280         }
281         server->stat.clients--;
282         if (server->server_type == SILC_ROUTER)
283           server->stat.cell_clients--;
284
285         if (!silc_idcache_list_next(list, &id_cache))
286           break;
287       }
288     }
289     silc_idcache_list_free(list);
290   }
291
292   /* Send the SERVER_SIGNOFF notify */
293   if (server_signoff) {
294     SilcBuffer args, not;
295
296     /* Send SERVER_SIGNOFF notify to our primary router */
297     if (!server->standalone && server->router &&
298         server->router != entry) {
299       args = silc_argument_payload_encode(1, argv, argv_lens,
300                                           argv_types);
301       silc_server_send_notify_args(server, 
302                                    server->router->connection,
303                                    server->server_type == SILC_SERVER ? 
304                                    FALSE : TRUE, 
305                                    SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
306                                    argc, args);
307       silc_buffer_free(args);
308     }
309
310     /* Send to local clients. We also send the list of client ID's that
311        is to be removed for those servers that would like to use that list. */
312     args = silc_argument_payload_encode(argc, argv, argv_lens,
313                                         argv_types);
314     not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
315                                           argc, args);
316     silc_server_packet_send_clients(server, clients, clients_c,
317                                     SILC_PACKET_NOTIFY, 0, FALSE,
318                                     not->data, not->len, FALSE);
319
320     silc_free(clients);
321     silc_buffer_free(args);
322     silc_buffer_free(not);
323     for (i = 0; i < argc; i++)
324       silc_free(argv[i]);
325     silc_free(argv);
326     silc_free(argv_lens);
327     silc_free(argv_types);
328   }
329
330   /* We must now re-generate the channel key for all channels that had
331      this server's client(s) on the channel. As they left the channel we
332      must re-generate the channel key. */
333   silc_hash_table_list(channels, &htl);
334   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
335     if (!silc_server_create_channel_key(server, channel, 0))
336       return FALSE;
337
338     /* Do not send the channel key if private channel key mode is set */
339     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
340       continue;
341
342     silc_server_send_channel_key(server, NULL, channel, 
343                                  server->server_type == SILC_ROUTER ? 
344                                  FALSE : !server->standalone);
345   }
346   silc_hash_table_free(channels);
347
348   return TRUE;
349 }
350
351 static SilcServerEntry
352 silc_server_update_clients_by_real_server(SilcServer server,
353                                           SilcServerEntry from,
354                                           SilcClientEntry client,
355                                           bool local,
356                                           SilcIDCacheEntry client_cache)
357 {
358   SilcServerEntry server_entry;
359   SilcIDCacheEntry id_cache = NULL;
360   SilcIDCacheList list;
361
362   if (!silc_idcache_get_all(server->local_list->servers, &list))
363     return NULL;
364
365   if (silc_idcache_list_first(list, &id_cache)) {
366     while (id_cache) {
367       server_entry = (SilcServerEntry)id_cache->context;
368       if (server_entry != from &&
369           SILC_ID_COMPARE(server_entry->id, client->id, 
370                           client->id->ip.data_len)) {
371         SILC_LOG_DEBUG(("Found (local) %s",
372                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
373
374         if (!server_entry->data.send_key && server_entry->router) {
375           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
376           /* If the client is not marked as local then move it to local list
377              since the server is local. */
378           if (!local) {
379             SILC_LOG_DEBUG(("Moving client to local list"));
380             silc_idcache_add(server->local_list->clients, client_cache->name,
381                              client_cache->id, client_cache->context,
382                              client_cache->expire, NULL);
383             silc_idcache_del_by_context(server->global_list->clients, client);
384           }
385           server_entry = server_entry->router;
386         } else {
387           /* If the client is not marked as local then move it to local list
388              since the server is local. */
389           if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
390             SILC_LOG_DEBUG(("Moving client to local list"));
391             silc_idcache_add(server->local_list->clients, client_cache->name,
392                              client_cache->id, client_cache->context,
393                              client_cache->expire, NULL);
394             silc_idcache_del_by_context(server->global_list->clients, client);
395           }
396         }
397
398         silc_idcache_list_free(list);
399         return server_entry;
400       }
401
402       if (!silc_idcache_list_next(list, &id_cache))
403         break;
404     }
405   }
406
407   silc_idcache_list_free(list);
408
409   if (!silc_idcache_get_all(server->global_list->servers, &list))
410     return NULL;
411
412   if (silc_idcache_list_first(list, &id_cache)) {
413     while (id_cache) {
414       server_entry = (SilcServerEntry)id_cache->context;
415       if (server_entry != from &&
416           SILC_ID_COMPARE(server_entry->id, client->id, 
417                           client->id->ip.data_len)) {
418         SILC_LOG_DEBUG(("Found (global) %s",
419                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
420
421         if (!server_entry->data.send_key && server_entry->router) {
422           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
423           /* If the client is marked as local then move it to global list
424              since the server is global. */
425           if (local) {
426             SILC_LOG_DEBUG(("Moving client to global list"));
427             silc_idcache_add(server->global_list->clients, client_cache->name,
428                              client_cache->id, client_cache->context,
429                              client_cache->expire, NULL);
430             silc_idcache_del_by_context(server->local_list->clients, client);
431           }
432           server_entry = server_entry->router;
433         } else {
434           /* If the client is marked as local then move it to global list
435              since the server is global. */
436           if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
437             SILC_LOG_DEBUG(("Moving client to global list"));
438             silc_idcache_add(server->global_list->clients, client_cache->name,
439                              client_cache->id, client_cache->context,
440                              client_cache->expire, NULL);
441             silc_idcache_del_by_context(server->local_list->clients, client);
442           }
443         }
444
445         silc_idcache_list_free(list);
446         return server_entry;
447       }
448
449       if (!silc_idcache_list_next(list, &id_cache))
450         break;
451     }
452   }
453
454   silc_idcache_list_free(list);
455
456   return NULL;
457 }
458
459 /* Updates the clients that are originated from the `from' to be originated
460    from the `to'. If the `resolve_real_server' is TRUE then this will
461    attempt to figure out which clients really are originated from the
462    `from' and which are originated from a server that we have connection
463    to, when we've acting as backup router. If it is FALSE the `to' will
464    be the new source. This function also removes the clients that are
465    *really* originated from `from' if `remove_from' is TRUE. These are
466    clients that the `from' owns, and not just clients that are behind
467    the `from'. */
468
469 void silc_server_update_clients_by_server(SilcServer server, 
470                                           SilcServerEntry from,
471                                           SilcServerEntry to,
472                                           bool resolve_real_server,
473                                           bool remove_from)
474 {
475   SilcIDCacheList list = NULL;
476   SilcIDCacheEntry id_cache = NULL;
477   SilcClientEntry client = NULL;
478   bool local;
479
480   SILC_LOG_DEBUG(("Start"));
481
482   SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
483                                                 SILC_ID_SERVER)));
484   SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
485                                           SILC_ID_SERVER)));
486
487
488   local = FALSE;
489   if (silc_idcache_get_all(server->global_list->clients, &list)) {
490     if (silc_idcache_list_first(list, &id_cache)) {
491       while (id_cache) {
492         client = (SilcClientEntry)id_cache->context;
493         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
494           if (!silc_idcache_list_next(list, &id_cache))
495             break;
496           else
497             continue;
498         }
499
500         SILC_LOG_DEBUG(("Client (global) %s", 
501                         silc_id_render(client->id, SILC_ID_CLIENT)));
502         if (client->router)
503           SILC_LOG_DEBUG(("Client->router (global) %s", 
504                           silc_id_render(client->router->id, SILC_ID_SERVER)));
505
506         if (client->router == from) {
507           /* Skip clients that are *really* owned by the `from' */
508           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
509                                              client->id->ip.data_len)) {
510             SILC_LOG_DEBUG(("Found really owned client, skip it"));
511             if (!silc_idcache_list_next(list, &id_cache))
512               break;
513             else
514               continue;
515           }
516
517           if (resolve_real_server) {
518             client->router = 
519               silc_server_update_clients_by_real_server(server, from, client,
520                                                         local, id_cache);
521             if (!client->router)
522               client->router = to;
523           } else {
524             client->router = to;
525           }
526         }
527
528         if (!silc_idcache_list_next(list, &id_cache))
529           break;
530       }
531     }
532     silc_idcache_list_free(list);
533   }
534
535   local = TRUE;
536   if (silc_idcache_get_all(server->local_list->clients, &list)) {
537     if (silc_idcache_list_first(list, &id_cache)) {
538       while (id_cache) {
539         client = (SilcClientEntry)id_cache->context;
540         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
541           if (!silc_idcache_list_next(list, &id_cache))
542             break;
543           else
544             continue;
545         }
546
547         SILC_LOG_DEBUG(("Client (local) %s", 
548                         silc_id_render(client->id, SILC_ID_CLIENT)));
549         if (client->router)
550           SILC_LOG_DEBUG(("Client->router (local) %s", 
551                           silc_id_render(client->router->id, SILC_ID_SERVER)));
552
553         if (client->router == from) {
554           /* Skip clients that are *really* owned by the `from' */
555           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
556                                              client->id->ip.data_len)) {
557             SILC_LOG_DEBUG(("Found really owned client, skip it"));
558             if (!silc_idcache_list_next(list, &id_cache))
559               break;
560             else
561               continue;
562           }
563
564           if (resolve_real_server) {
565             client->router = 
566               silc_server_update_clients_by_real_server(server, from, client,
567                                                         local, id_cache);
568             if (!client->router)
569               client->router = from; /* on local list put old from */
570           } else {
571             client->router = to;
572           }
573         }
574
575         if (!silc_idcache_list_next(list, &id_cache))
576           break;
577       }
578     }
579     silc_idcache_list_free(list);
580   }
581
582   if (remove_from)
583     /* Now remove the clients that are still marked as orignated from the
584        `from'. These are the clients that really was owned by the `from' and
585        not just exist behind the `from'. */
586     silc_server_remove_clients_by_server(server, from, TRUE);
587 }
588
589 /* Updates servers that are from `from' to be originated from `to'.  This
590    will also update the server's connection to `to's connection. */
591
592 void silc_server_update_servers_by_server(SilcServer server, 
593                                           SilcServerEntry from,
594                                           SilcServerEntry to)
595 {
596   SilcIDCacheList list = NULL;
597   SilcIDCacheEntry id_cache = NULL;
598   SilcServerEntry server_entry = NULL;
599
600   SILC_LOG_DEBUG(("Start"));
601
602   if (silc_idcache_get_all(server->local_list->servers, &list)) {
603     if (silc_idcache_list_first(list, &id_cache)) {
604       while (id_cache) {
605         server_entry = (SilcServerEntry)id_cache->context;
606         if (server_entry->router == from) {
607           server_entry->router = to;
608           server_entry->connection = to->connection;
609         }
610         if (!silc_idcache_list_next(list, &id_cache))
611           break;
612       }
613     }
614     silc_idcache_list_free(list);
615   }
616
617   if (silc_idcache_get_all(server->global_list->servers, &list)) {
618     if (silc_idcache_list_first(list, &id_cache)) {
619       while (id_cache) {
620         server_entry = (SilcServerEntry)id_cache->context;
621         if (server_entry->router == from) {
622           server_entry->router = to;
623           server_entry->connection = to->connection;
624         }
625         if (!silc_idcache_list_next(list, &id_cache))
626           break;
627       }
628     }
629     silc_idcache_list_free(list);
630   }
631 }
632
633 /* Removes channels that are from `from. */
634
635 void silc_server_remove_channels_by_server(SilcServer server, 
636                                            SilcServerEntry from)
637 {
638   SilcIDCacheList list = NULL;
639   SilcIDCacheEntry id_cache = NULL;
640   SilcChannelEntry channel = NULL;
641
642   SILC_LOG_DEBUG(("Start"));
643
644   if (silc_idcache_get_all(server->global_list->channels, &list)) {
645     if (silc_idcache_list_first(list, &id_cache)) {
646       while (id_cache) {
647         channel = (SilcChannelEntry)id_cache->context;
648         if (channel->router == from)
649           silc_idlist_del_channel(server->global_list, channel);
650         if (!silc_idcache_list_next(list, &id_cache))
651           break;
652       }
653     }
654     silc_idcache_list_free(list);
655   }
656 }
657
658 /* Updates channels that are from `from' to be originated from `to'.  */
659
660 void silc_server_update_channels_by_server(SilcServer server, 
661                                            SilcServerEntry from,
662                                            SilcServerEntry to)
663 {
664   SilcIDCacheList list = NULL;
665   SilcIDCacheEntry id_cache = NULL;
666   SilcChannelEntry channel = NULL;
667
668   SILC_LOG_DEBUG(("Start"));
669
670   if (silc_idcache_get_all(server->global_list->channels, &list)) {
671     if (silc_idcache_list_first(list, &id_cache)) {
672       while (id_cache) {
673         channel = (SilcChannelEntry)id_cache->context;
674         if (channel->router == from)
675           channel->router = to;
676         if (!silc_idcache_list_next(list, &id_cache))
677           break;
678       }
679     }
680     silc_idcache_list_free(list);
681   }
682 }
683
684 /* Checks whether given channel has global users.  If it does this returns
685    TRUE and FALSE if there is only locally connected clients on the channel. */
686
687 bool silc_server_channel_has_global(SilcChannelEntry channel)
688 {
689   SilcChannelClientEntry chl;
690   SilcHashTableList htl;
691
692   silc_hash_table_list(channel->user_list, &htl);
693   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
694     if (chl->client->router)
695       return TRUE;
696   }
697
698   return FALSE;
699 }
700
701 /* Checks whether given channel has locally connected users.  If it does this
702    returns TRUE and FALSE if there is not one locally connected client. */
703
704 bool silc_server_channel_has_local(SilcChannelEntry channel)
705 {
706   SilcChannelClientEntry chl;
707   SilcHashTableList htl;
708
709   silc_hash_table_list(channel->user_list, &htl);
710   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
711     if (!chl->client->router)
712       return TRUE;
713   }
714
715   return FALSE;
716 }
717
718 /* Returns TRUE if the given client is on the channel.  FALSE if not. 
719    This works because we assure that the user list on the channel is
720    always in up to date thus we can only check the channel list from 
721    `client' which is faster than checking the user list from `channel'. */
722
723 bool silc_server_client_on_channel(SilcClientEntry client,
724                                    SilcChannelEntry channel)
725 {
726   if (!client || !channel)
727     return FALSE;
728
729   if (silc_hash_table_find(client->channels, channel, NULL, NULL))
730     return TRUE;
731
732   return FALSE;
733 }
734
735 /* Checks string for bad characters and returns TRUE if they are found. */
736
737 bool silc_server_name_bad_chars(const char *name, uint32 name_len)
738 {
739   int i;
740
741   for (i = 0; i < name_len; i++) {
742     if (!isascii(name[i]))
743       return TRUE;
744     if (name[i] <= 32) return TRUE;
745     if (name[i] == ' ') return TRUE;
746     if (name[i] == '*') return TRUE;
747     if (name[i] == '?') return TRUE;
748     if (name[i] == ',') return TRUE;
749   }
750
751   return FALSE;
752 }
753
754 /* Modifies the `name' if it includes bad characters and returns new
755    allocated name that does not include bad characters. */
756
757 char *silc_server_name_modify_bad(const char *name, uint32 name_len)
758 {
759   int i;
760   char *newname = strdup(name);
761
762   for (i = 0; i < name_len; i++) {
763     if (!isascii(newname[i])) newname[i] = '_';
764     if (newname[i] <= 32) newname[i] = '_';
765     if (newname[i] == ' ') newname[i] = '_';
766     if (newname[i] == '*') newname[i] = '_';
767     if (newname[i] == '?') newname[i] = '_';
768     if (newname[i] == ',') newname[i] = '_';
769   }
770
771   return newname;
772 }