ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
Revision: 2616
Committed: Wed Dec 4 17:52:24 2013 UTC (11 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 20249 byte(s)
Log Message:
- Administrators may now see channel modes in /LIST

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

Properties

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