ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/hash.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 23007 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


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

Properties

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