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