ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/hash.c
Revision: 470
Committed: Fri Feb 17 05:07:43 2006 UTC (19 years, 6 months ago) by db
Content type: text/x-csrc
File size: 22847 byte(s)
Log Message:
- fix compile errors with moved modules.h
- fix a few missing includes, msg.h and parse.h


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

Properties

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