ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/hash.c
Revision: 33
Committed: Sun Oct 2 20:50:00 2005 UTC (18 years, 6 months ago) by knight
Content type: text/x-csrc
Original Path: ircd-hybrid/src/hash.c
File size: 23007 byte(s)
Log Message:
- svn:keywords

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
23 adx 30 */
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