ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/hash.c
Revision: 1332
Committed: Sun Apr 1 16:25:50 2012 UTC (13 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 21501 byte(s)
Log Message:
- init_hash(): remove unused variable

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * hash.c: Maintains hashtables.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h"
27 #include "balloc.h"
28 #include "conf.h"
29 #include "channel.h"
30 #include "channel_mode.h"
31 #include "client.h"
32 #include "modules.h"
33 #include "hash.h"
34 #include "resv.h"
35 #include "rng_mt.h"
36 #include "userhost.h"
37 #include "irc_string.h"
38 #include "ircd.h"
39 #include "numeric.h"
40 #include "send.h"
41 #include "memory.h"
42 #include "dbuf.h"
43 #include "s_user.h"
44
45
46 static BlockHeap *userhost_heap = NULL;
47 static BlockHeap *namehost_heap = NULL;
48 static struct UserHost *find_or_add_userhost(const char *);
49
50 static unsigned int hashf_xor_key = 0;
51
52 /* The actual hash tables, They MUST be of the same HASHSIZE, variable
53 * size tables could be supported but the rehash routine should also
54 * rebuild the transformation maps, I kept the tables of equal size
55 * so that I can use one hash function.
56 */
57 static struct Client *idTable[HASHSIZE];
58 static struct Client *clientTable[HASHSIZE];
59 static struct Channel *channelTable[HASHSIZE];
60 static struct UserHost *userhostTable[HASHSIZE];
61 static struct ResvChannel *resvchannelTable[HASHSIZE];
62
63
64 /* init_hash()
65 *
66 * inputs - NONE
67 * output - NONE
68 * side effects - Initialize the maps used by hash
69 * functions and clear the tables
70 */
71 void
72 init_hash(void)
73 {
74 /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now,
75 * should be a good close approximation anyway
76 * - Dianora
77 */
78 userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE);
79 namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE);
80
81 hashf_xor_key = genrand_int32() % 256; /* better than nothing --adx */
82 }
83
84 /*
85 * New hash function based on the Fowler/Noll/Vo (FNV) algorithm from
86 * http://www.isthe.com/chongo/tech/comp/fnv/
87 *
88 * Here, we use the FNV-1 method, which gives slightly better results
89 * than FNV-1a. -Michael
90 */
91 unsigned int
92 strhash(const char *name)
93 {
94 const unsigned char *p = (const unsigned char *)name;
95 unsigned int hval = FNV1_32_INIT;
96
97 if (*p == '\0')
98 return 0;
99 for (; *p != '\0'; ++p)
100 {
101 hval += (hval << 1) + (hval << 4) + (hval << 7) +
102 (hval << 8) + (hval << 24);
103 hval ^= (ToLower(*p) ^ hashf_xor_key);
104 }
105
106 return (hval >> FNV1_32_BITS) ^ (hval & ((1 << FNV1_32_BITS) - 1));
107 }
108
109 /************************** Externally visible functions ********************/
110
111 /* Optimization note: in these functions I supposed that the CSE optimization
112 * (Common Subexpression Elimination) does its work decently, this means that
113 * I avoided introducing new variables to do the work myself and I did let
114 * the optimizer play with more free registers, actual tests proved this
115 * solution to be faster than doing things like tmp2=tmp->hnext... and then
116 * use tmp2 myself which would have given less freedom to the optimizer.
117 */
118
119 /* hash_add_client()
120 *
121 * inputs - pointer to client
122 * output - NONE
123 * side effects - Adds a client's name in the proper hash linked
124 * list, can't fail, client_p must have a non-null
125 * name or expect a coredump, the name is infact
126 * taken from client_p->name
127 */
128 void
129 hash_add_client(struct Client *client_p)
130 {
131 unsigned int hashv = strhash(client_p->name);
132
133 client_p->hnext = clientTable[hashv];
134 clientTable[hashv] = client_p;
135 }
136
137 /* hash_add_channel()
138 *
139 * inputs - pointer to channel
140 * output - NONE
141 * side effects - Adds a channel's name in the proper hash linked
142 * list, can't fail. chptr must have a non-null name
143 * or expect a coredump. As before the name is taken
144 * from chptr->name, we do hash its entire lenght
145 * since this proved to be statistically faster
146 */
147 void
148 hash_add_channel(struct Channel *chptr)
149 {
150 unsigned int hashv = strhash(chptr->chname);
151
152 chptr->hnextch = channelTable[hashv];
153 channelTable[hashv] = chptr;
154 }
155
156 void
157 hash_add_resv(struct ResvChannel *chptr)
158 {
159 unsigned int hashv = strhash(chptr->name);
160
161 chptr->hnext = resvchannelTable[hashv];
162 resvchannelTable[hashv] = chptr;
163 }
164
165 void
166 hash_add_userhost(struct UserHost *userhost)
167 {
168 unsigned int hashv = strhash(userhost->host);
169
170 userhost->next = userhostTable[hashv];
171 userhostTable[hashv] = userhost;
172 }
173
174 void
175 hash_add_id(struct Client *client_p)
176 {
177 unsigned int hashv = strhash(client_p->id);
178
179 client_p->idhnext = idTable[hashv];
180 idTable[hashv] = client_p;
181 }
182
183 /* hash_del_id()
184 *
185 * inputs - pointer to client
186 * output - NONE
187 * side effects - Removes an ID from the hash linked list
188 */
189 void
190 hash_del_id(struct Client *client_p)
191 {
192 unsigned int hashv = strhash(client_p->id);
193 struct Client *tmp = idTable[hashv];
194
195 if (tmp != NULL)
196 {
197 if (tmp == client_p)
198 {
199 idTable[hashv] = client_p->idhnext;
200 client_p->idhnext = client_p;
201 }
202 else
203 {
204 while (tmp->idhnext != client_p)
205 if ((tmp = tmp->idhnext) == NULL)
206 return;
207
208 tmp->idhnext = tmp->idhnext->idhnext;
209 client_p->idhnext = client_p;
210 }
211 }
212 }
213
214 /* hash_del_client()
215 *
216 * inputs - pointer to client
217 * output - NONE
218 * side effects - Removes a Client's name from the hash linked list
219 */
220 void
221 hash_del_client(struct Client *client_p)
222 {
223 unsigned int hashv = strhash(client_p->name);
224 struct Client *tmp = clientTable[hashv];
225
226 if (tmp != NULL)
227 {
228 if (tmp == client_p)
229 {
230 clientTable[hashv] = client_p->hnext;
231 client_p->hnext = client_p;
232 }
233 else
234 {
235 while (tmp->hnext != client_p)
236 if ((tmp = tmp->hnext) == NULL)
237 return;
238
239 tmp->hnext = tmp->hnext->hnext;
240 client_p->hnext = client_p;
241 }
242 }
243 }
244
245 /* hash_del_userhost()
246 *
247 * inputs - pointer to userhost
248 * output - NONE
249 * side effects - Removes a userhost from the hash linked list
250 */
251 void
252 hash_del_userhost(struct UserHost *userhost)
253 {
254 unsigned int hashv = strhash(userhost->host);
255 struct UserHost *tmp = userhostTable[hashv];
256
257 if (tmp != NULL)
258 {
259 if (tmp == userhost)
260 {
261 userhostTable[hashv] = userhost->next;
262 userhost->next = userhost;
263 }
264 else
265 {
266 while (tmp->next != userhost)
267 if ((tmp = tmp->next) == NULL)
268 return;
269
270 tmp->next = tmp->next->next;
271 userhost->next = userhost;
272 }
273 }
274 }
275
276 /* hash_del_channel()
277 *
278 * inputs - pointer to client
279 * output - NONE
280 * side effects - Removes the channel's name from the corresponding
281 * hash linked list
282 */
283 void
284 hash_del_channel(struct Channel *chptr)
285 {
286 unsigned int hashv = strhash(chptr->chname);
287 struct Channel *tmp = channelTable[hashv];
288
289 if (tmp != NULL)
290 {
291 if (tmp == chptr)
292 {
293 channelTable[hashv] = chptr->hnextch;
294 chptr->hnextch = chptr;
295 }
296 else
297 {
298 while (tmp->hnextch != chptr)
299 if ((tmp = tmp->hnextch) == NULL)
300 return;
301
302 tmp->hnextch = tmp->hnextch->hnextch;
303 chptr->hnextch = chptr;
304 }
305 }
306 }
307
308 void
309 hash_del_resv(struct ResvChannel *chptr)
310 {
311 unsigned int hashv = strhash(chptr->name);
312 struct ResvChannel *tmp = resvchannelTable[hashv];
313
314 if (tmp != NULL)
315 {
316 if (tmp == chptr)
317 {
318 resvchannelTable[hashv] = chptr->hnext;
319 chptr->hnext = chptr;
320 }
321 else
322 {
323 while (tmp->hnext != chptr)
324 if ((tmp = tmp->hnext) == NULL)
325 return;
326
327 tmp->hnext = tmp->hnext->hnext;
328 chptr->hnext = chptr;
329 }
330 }
331 }
332
333 /* hash_find_client()
334 *
335 * inputs - pointer to name
336 * output - NONE
337 * side effects - New semantics: finds a client whose name is 'name'
338 * if can't find one returns NULL. If it finds one moves
339 * it to the top of the list and returns it.
340 */
341 struct Client *
342 hash_find_client(const char *name)
343 {
344 unsigned int hashv = strhash(name);
345 struct Client *client_p;
346
347 if ((client_p = clientTable[hashv]) != NULL)
348 {
349 if (irccmp(name, client_p->name))
350 {
351 struct Client *prev;
352
353 while (prev = client_p, (client_p = client_p->hnext) != NULL)
354 {
355 if (!irccmp(name, client_p->name))
356 {
357 prev->hnext = client_p->hnext;
358 client_p->hnext = clientTable[hashv];
359 clientTable[hashv] = client_p;
360 break;
361 }
362 }
363 }
364 }
365
366 return client_p;
367 }
368
369 struct Client *
370 hash_find_id(const char *name)
371 {
372 unsigned int hashv = strhash(name);
373 struct Client *client_p;
374
375 if ((client_p = idTable[hashv]) != NULL)
376 {
377 if (strcmp(name, client_p->id))
378 {
379 struct Client *prev;
380
381 while (prev = client_p, (client_p = client_p->idhnext) != NULL)
382 {
383 if (!strcmp(name, client_p->id))
384 {
385 prev->idhnext = client_p->idhnext;
386 client_p->idhnext = idTable[hashv];
387 idTable[hashv] = client_p;
388 break;
389 }
390 }
391 }
392 }
393
394 return client_p;
395 }
396
397 struct Client *
398 hash_find_server(const char *name)
399 {
400 unsigned int hashv = strhash(name);
401 struct Client *client_p = NULL;
402
403 if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
404 client_p = hash_find_id(name);
405
406 if ((client_p == NULL) && (client_p = clientTable[hashv]) != NULL)
407 {
408 if ((!IsServer(client_p) && !IsMe(client_p)) ||
409 irccmp(name, client_p->name))
410 {
411 struct Client *prev;
412
413 while (prev = client_p, (client_p = client_p->hnext) != NULL)
414 {
415 if ((IsServer(client_p) || IsMe(client_p)) &&
416 !irccmp(name, client_p->name))
417 {
418 prev->hnext = client_p->hnext;
419 client_p->hnext = clientTable[hashv];
420 clientTable[hashv] = client_p;
421 break;
422 }
423 }
424 }
425 }
426
427 return client_p;
428 }
429
430 /* hash_find_channel()
431 *
432 * inputs - pointer to name
433 * output - NONE
434 * side effects - New semantics: finds a channel whose name is 'name',
435 * if can't find one returns NULL, if can find it moves
436 * it to the top of the list and returns it.
437 */
438 struct Channel *
439 hash_find_channel(const char *name)
440 {
441 unsigned int hashv = strhash(name);
442 struct Channel *chptr = NULL;
443
444 if ((chptr = channelTable[hashv]) != NULL)
445 {
446 if (irccmp(name, chptr->chname))
447 {
448 struct Channel *prev;
449
450 while (prev = chptr, (chptr = chptr->hnextch) != NULL)
451 {
452 if (!irccmp(name, chptr->chname))
453 {
454 prev->hnextch = chptr->hnextch;
455 chptr->hnextch = channelTable[hashv];
456 channelTable[hashv] = chptr;
457 break;
458 }
459 }
460 }
461 }
462
463 return chptr;
464 }
465
466 /* hash_get_bucket(int type, unsigned int hashv)
467 *
468 * inputs - hash value (must be between 0 and HASHSIZE - 1)
469 * output - NONE
470 * returns - pointer to first channel in channelTable[hashv]
471 * if that exists;
472 * NULL if there is no channel in that place;
473 * NULL if hashv is an invalid number.
474 * side effects - NONE
475 */
476 void *
477 hash_get_bucket(int type, unsigned int hashv)
478 {
479 assert(hashv < HASHSIZE);
480 if (hashv >= HASHSIZE)
481 return NULL;
482
483 switch (type)
484 {
485 case HASH_TYPE_ID:
486 return idTable[hashv];
487 break;
488 case HASH_TYPE_CHANNEL:
489 return channelTable[hashv];
490 break;
491 case HASH_TYPE_CLIENT:
492 return clientTable[hashv];
493 break;
494 case HASH_TYPE_USERHOST:
495 return userhostTable[hashv];
496 break;
497 case HASH_TYPE_RESERVED:
498 return resvchannelTable[hashv];
499 break;
500 default:
501 assert(0);
502 }
503
504 return NULL;
505 }
506
507 /* hash_find_resv()
508 *
509 * inputs - pointer to name
510 * output - NONE
511 * side effects - New semantics: finds a reserved channel whose name is 'name',
512 * if can't find one returns NULL, if can find it moves
513 * it to the top of the list and returns it.
514 */
515 struct ResvChannel *
516 hash_find_resv(const char *name)
517 {
518 unsigned int hashv = strhash(name);
519 struct ResvChannel *chptr;
520
521 if ((chptr = resvchannelTable[hashv]) != NULL)
522 {
523 if (irccmp(name, chptr->name))
524 {
525 struct ResvChannel *prev;
526
527 while (prev = chptr, (chptr = chptr->hnext) != NULL)
528 {
529 if (!irccmp(name, chptr->name))
530 {
531 prev->hnext = chptr->hnext;
532 chptr->hnext = resvchannelTable[hashv];
533 resvchannelTable[hashv] = chptr;
534 break;
535 }
536 }
537 }
538 }
539
540 return chptr;
541 }
542
543 struct UserHost *
544 hash_find_userhost(const char *host)
545 {
546 unsigned int hashv = strhash(host);
547 struct UserHost *userhost;
548
549 if ((userhost = userhostTable[hashv]))
550 {
551 if (irccmp(host, userhost->host))
552 {
553 struct UserHost *prev;
554
555 while (prev = userhost, (userhost = userhost->next) != NULL)
556 {
557 if (!irccmp(host, userhost->host))
558 {
559 prev->next = userhost->next;
560 userhost->next = userhostTable[hashv];
561 userhostTable[hashv] = userhost;
562 break;
563 }
564 }
565 }
566 }
567
568 return userhost;
569 }
570
571 /* count_user_host()
572 *
573 * inputs - user name
574 * - hostname
575 * - int flag 1 if global, 0 if local
576 * - pointer to where global count should go
577 * - pointer to where local count should go
578 * - pointer to where identd count should go (local clients only)
579 * output - none
580 * side effects -
581 */
582 void
583 count_user_host(const char *user, const char *host, int *global_p,
584 int *local_p, int *icount_p)
585 {
586 dlink_node *ptr;
587 struct UserHost *found_userhost;
588 struct NameHost *nameh;
589
590 if ((found_userhost = hash_find_userhost(host)) == NULL)
591 return;
592
593 DLINK_FOREACH(ptr, found_userhost->list.head)
594 {
595 nameh = ptr->data;
596
597 if (!irccmp(user, nameh->name))
598 {
599 if (global_p != NULL)
600 *global_p = nameh->gcount;
601 if (local_p != NULL)
602 *local_p = nameh->lcount;
603 if (icount_p != NULL)
604 *icount_p = nameh->icount;
605 return;
606 }
607 }
608 }
609
610 /* add_user_host()
611 *
612 * inputs - user name
613 * - hostname
614 * - int flag 1 if global, 0 if local
615 * output - none
616 * side effects - add given user@host to hash tables
617 */
618 void
619 add_user_host(const char *user, const char *host, int global)
620 {
621 dlink_node *ptr;
622 struct UserHost *found_userhost;
623 struct NameHost *nameh;
624 int hasident = 1;
625
626 if (*user == '~')
627 {
628 hasident = 0;
629 ++user;
630 }
631
632 if ((found_userhost = find_or_add_userhost(host)) == NULL)
633 return;
634
635 DLINK_FOREACH(ptr, found_userhost->list.head)
636 {
637 nameh = ptr->data;
638
639 if (!irccmp(user, nameh->name))
640 {
641 nameh->gcount++;
642 if (!global)
643 {
644 if (hasident)
645 nameh->icount++;
646 nameh->lcount++;
647 }
648 return;
649 }
650 }
651
652 nameh = BlockHeapAlloc(namehost_heap);
653 strlcpy(nameh->name, user, sizeof(nameh->name));
654
655 nameh->gcount = 1;
656 if (!global)
657 {
658 if (hasident)
659 nameh->icount = 1;
660 nameh->lcount = 1;
661 }
662
663 dlinkAdd(nameh, &nameh->node, &found_userhost->list);
664 }
665
666 /* delete_user_host()
667 *
668 * inputs - user name
669 * - hostname
670 * - int flag 1 if global, 0 if local
671 * output - none
672 * side effects - delete given user@host to hash tables
673 */
674 void
675 delete_user_host(const char *user, const char *host, int global)
676 {
677 dlink_node *ptr = NULL, *next_ptr = NULL;
678 struct UserHost *found_userhost;
679 struct NameHost *nameh;
680 int hasident = 1;
681
682 if (*user == '~')
683 {
684 hasident = 0;
685 ++user;
686 }
687
688 if ((found_userhost = hash_find_userhost(host)) == NULL)
689 return;
690
691 DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
692 {
693 nameh = ptr->data;
694
695 if (!irccmp(user, nameh->name))
696 {
697 if (nameh->gcount > 0)
698 nameh->gcount--;
699 if (!global)
700 {
701 if (nameh->lcount > 0)
702 nameh->lcount--;
703 if (hasident && nameh->icount > 0)
704 nameh->icount--;
705 }
706
707 if (nameh->gcount == 0 && nameh->lcount == 0)
708 {
709 dlinkDelete(&nameh->node, &found_userhost->list);
710 BlockHeapFree(namehost_heap, nameh);
711 }
712
713 if (dlink_list_length(&found_userhost->list) == 0)
714 {
715 hash_del_userhost(found_userhost);
716 BlockHeapFree(userhost_heap, found_userhost);
717 }
718
719 return;
720 }
721 }
722 }
723
724 /* find_or_add_userhost()
725 *
726 * inputs - host name
727 * output - none
728 * side effects - find UserHost * for given host name
729 */
730 static struct UserHost *
731 find_or_add_userhost(const char *host)
732 {
733 struct UserHost *userhost;
734
735 if ((userhost = hash_find_userhost(host)) != NULL)
736 return userhost;
737
738 userhost = BlockHeapAlloc(userhost_heap);
739 strlcpy(userhost->host, host, sizeof(userhost->host));
740 hash_add_userhost(userhost);
741
742 return userhost;
743 }
744
745 /*
746 * Safe list code.
747 *
748 * The idea is really quite simple. As the link lists pointed to in
749 * each "bucket" of the channel hash table are traversed atomically
750 * there is no locking needed. Overall, yes, inconsistent reported
751 * state can still happen, but normally this isn't a big deal.
752 * I don't like sticking the code into hash.c but oh well. Moreover,
753 * if a hash isn't used in future, oops.
754 *
755 * - Dianora
756 */
757
758 /* exceeding_sendq()
759 *
760 * inputs - pointer to client to check
761 * output - 1 if client is in danger of blowing its sendq
762 * 0 if it is not.
763 * side effects -
764 *
765 * Sendq limit is fairly conservative at 1/2 (In original anyway)
766 */
767 static int
768 exceeding_sendq(struct Client *to)
769 {
770 if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2))
771 return 1;
772 else
773 return 0;
774 }
775
776 void
777 free_list_task(struct ListTask *lt, struct Client *source_p)
778 {
779 dlink_node *dl, *dln;
780
781 if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL)
782 free_dlink_node(dl);
783
784 DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head)
785 {
786 MyFree(dl->data);
787 free_dlink_node(dl);
788 }
789
790 DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head)
791 {
792 MyFree(dl->data);
793 free_dlink_node(dl);
794 }
795
796 MyFree(lt);
797
798 if (MyConnect(source_p))
799 source_p->localClient->list_task = NULL;
800 }
801
802 /* list_allow_channel()
803 *
804 * inputs - channel name
805 * - pointer to a list task
806 * output - 1 if the channel is to be displayed
807 * 0 otherwise
808 * side effects -
809 */
810 static int
811 list_allow_channel(const char *chname, struct ListTask *lt)
812 {
813 dlink_node *dl = NULL;
814
815 DLINK_FOREACH(dl, lt->show_mask.head)
816 if (!match_chan(dl->data, chname))
817 return 0;
818
819 DLINK_FOREACH(dl, lt->hide_mask.head)
820 if (match_chan(dl->data, chname))
821 return 0;
822
823 return 1;
824 }
825
826 /* list_one_channel()
827 *
828 * inputs - client pointer to return result to
829 * - pointer to channel to list
830 * - pointer to ListTask structure
831 * output - none
832 * side effects -
833 */
834 static void
835 list_one_channel(struct Client *source_p, struct Channel *chptr,
836 struct ListTask *list_task)
837 {
838 if (SecretChannel(chptr) && !IsMember(source_p, chptr))
839 return;
840 if (dlink_list_length(&chptr->members) < list_task->users_min ||
841 dlink_list_length(&chptr->members) > list_task->users_max ||
842 (chptr->channelts != 0 &&
843 ((unsigned int)chptr->channelts < list_task->created_min ||
844 (unsigned int)chptr->channelts > list_task->created_max)) ||
845 (unsigned int)chptr->topic_time < list_task->topicts_min ||
846 (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
847 list_task->topicts_max)
848 return;
849
850 if (!list_allow_channel(chptr->chname, list_task))
851 return;
852 sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
853 chptr->chname, dlink_list_length(&chptr->members),
854 chptr->topic);
855 }
856
857 /* safe_list_channels()
858 *
859 * inputs - pointer to client requesting list
860 * output - 0/1
861 * side effects - safely list all channels to source_p
862 *
863 * Walk the channel buckets, ensure all pointers in a bucket are
864 * traversed before blocking on a sendq. This means, no locking is needed.
865 *
866 * N.B. This code is "remote" safe, but is not currently used for
867 * remote clients.
868 *
869 * - Dianora
870 */
871 void
872 safe_list_channels(struct Client *source_p, struct ListTask *list_task,
873 int only_unmasked_channels)
874 {
875 struct Channel *chptr = NULL;
876
877 if (!only_unmasked_channels)
878 {
879 unsigned int i;
880
881 for (i = list_task->hash_index; i < HASHSIZE; ++i)
882 {
883 if (exceeding_sendq(source_p->from))
884 {
885 list_task->hash_index = i;
886 return; /* still more to do */
887 }
888
889 for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
890 list_one_channel(source_p, chptr, list_task);
891 }
892 }
893 else
894 {
895 dlink_node *dl;
896
897 DLINK_FOREACH(dl, list_task->show_mask.head)
898 if ((chptr = hash_find_channel(dl->data)) != NULL)
899 list_one_channel(source_p, chptr, list_task);
900 }
901
902 free_list_task(list_task, source_p);
903 sendto_one(source_p, form_str(RPL_LISTEND),
904 me.name, source_p->name);
905 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision