ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hash.c
(Generate patch)

Comparing ircd-hybrid/trunk/src/hash.c (file contents):
Revision 1592 by michael, Sat Oct 27 21:02:32 2012 UTC vs.
Revision 7484 by michael, Wed Mar 16 09:28:14 2016 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  hash.c: Maintains hashtables.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2002 by the past and present ircd coders, and others.
4 > *  Copyright (c) 1997-2016 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 16 | Line 15
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18 < *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
20 > */
21 >
22 > /*! \file hash.c
23 > * \brief Hash table management.
24 > * \version $Id$
25   */
26  
27   #include "stdinc.h"
28   #include "list.h"
27 #include "balloc.h"
29   #include "conf.h"
30   #include "channel.h"
31   #include "channel_mode.h"
32   #include "client.h"
32 #include "modules.h"
33   #include "hash.h"
34 < #include "resv.h"
34 > #include "id.h"
35   #include "rng_mt.h"
36   #include "userhost.h"
37   #include "irc_string.h"
# Line 40 | Line 40
40   #include "send.h"
41   #include "memory.h"
42   #include "dbuf.h"
43 #include "s_user.h"
44
43  
46 static BlockHeap *userhost_heap = NULL;
47 static BlockHeap *namehost_heap = NULL;
44  
45 < static unsigned int hashf_xor_key = 0;
45 > static unsigned int hashf_xor_key;
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
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];
60 static struct ResvChannel *resvchannelTable[HASHSIZE];
56  
57  
58 < /* init_hash()
58 > /* hash_init()
59   *
60   * inputs       - NONE
61   * output       - NONE
# Line 68 | Line 63 | static struct ResvChannel *resvchannelTa
63   *                functions and clear the tables
64   */
65   void
66 < init_hash(void)
66 > hash_init(void)
67   {
68 <  /* Default the userhost/namehost sizes to CLIENT_HEAP_SIZE for now,
69 <   * should be a good close approximation anyway
70 <   * - Dianora
76 <   */
77 <  userhost_heap = BlockHeapCreate("userhost", sizeof(struct UserHost), CLIENT_HEAP_SIZE);
78 <  namehost_heap = BlockHeapCreate("namehost", sizeof(struct NameHost), CLIENT_HEAP_SIZE);
79 <
80 <  hashf_xor_key = genrand_int32() % 256;  /* better than nothing --adx */
68 >  do
69 >    hashf_xor_key = genrand_int32() % 256;  /* better than nothing --adx */
70 >  while (!hashf_xor_key);
71   }
72  
73   /*
# Line 93 | Line 83 | strhash(const char *name)
83    const unsigned char *p = (const unsigned char *)name;
84    unsigned int hval = FNV1_32_INIT;
85  
86 <  if (*p == '\0')
86 >  if (EmptyString(p))
87      return 0;
88 <  for (; *p != '\0'; ++p)
88 >
89 >  for (; *p; ++p)
90    {
91      hval += (hval << 1) + (hval <<  4) + (hval << 7) +
92              (hval << 8) + (hval << 24);
# Line 127 | Line 118 | strhash(const char *name)
118   void
119   hash_add_client(struct Client *client_p)
120   {
121 <  unsigned int hashv = strhash(client_p->name);
121 >  const unsigned int hashv = strhash(client_p->name);
122  
123    client_p->hnext = clientTable[hashv];
124    clientTable[hashv] = client_p;
# Line 146 | Line 137 | hash_add_client(struct Client *client_p)
137   void
138   hash_add_channel(struct Channel *chptr)
139   {
140 <  unsigned int hashv = strhash(chptr->chname);
140 >  const unsigned int hashv = strhash(chptr->name);
141  
142    chptr->hnextch = channelTable[hashv];
143    channelTable[hashv] = chptr;
144   }
145  
146   void
156 hash_add_resv(struct ResvChannel *chptr)
157 {
158  unsigned int hashv = strhash(chptr->name);
159
160  chptr->hnext = resvchannelTable[hashv];
161  resvchannelTable[hashv] = chptr;
162 }
163
164 void
147   hash_add_userhost(struct UserHost *userhost)
148   {
149 <  unsigned int hashv = strhash(userhost->host);
149 >  const unsigned int hashv = strhash(userhost->host);
150  
151    userhost->next = userhostTable[hashv];
152    userhostTable[hashv] = userhost;
# Line 173 | Line 155 | hash_add_userhost(struct UserHost *userh
155   void
156   hash_add_id(struct Client *client_p)
157   {
158 <  unsigned int hashv = strhash(client_p->id);
158 >  const unsigned int hashv = strhash(client_p->id);
159  
160    client_p->idhnext = idTable[hashv];
161    idTable[hashv] = client_p;
# Line 188 | Line 170 | hash_add_id(struct Client *client_p)
170   void
171   hash_del_id(struct Client *client_p)
172   {
173 <  unsigned int hashv = strhash(client_p->id);
173 >  const unsigned int hashv = strhash(client_p->id);
174    struct Client *tmp = idTable[hashv];
175  
176 <  if (tmp != NULL)
176 >  if (tmp)
177    {
178      if (tmp == client_p)
179      {
# Line 219 | Line 201 | hash_del_id(struct Client *client_p)
201   void
202   hash_del_client(struct Client *client_p)
203   {
204 <  unsigned int hashv = strhash(client_p->name);
204 >  const unsigned int hashv = strhash(client_p->name);
205    struct Client *tmp = clientTable[hashv];
206  
207 <  if (tmp != NULL)
207 >  if (tmp)
208    {
209      if (tmp == client_p)
210      {
# Line 250 | Line 232 | hash_del_client(struct Client *client_p)
232   void
233   hash_del_userhost(struct UserHost *userhost)
234   {
235 <  unsigned int hashv = strhash(userhost->host);
235 >  const unsigned int hashv = strhash(userhost->host);
236    struct UserHost *tmp = userhostTable[hashv];
237  
238 <  if (tmp != NULL)
238 >  if (tmp)
239    {
240      if (tmp == userhost)
241      {
# Line 282 | Line 264 | hash_del_userhost(struct UserHost *userh
264   void
265   hash_del_channel(struct Channel *chptr)
266   {
267 <  unsigned int hashv = strhash(chptr->chname);
267 >  const unsigned int hashv = strhash(chptr->name);
268    struct Channel *tmp = channelTable[hashv];
269  
270 <  if (tmp != NULL)
270 >  if (tmp)
271    {
272      if (tmp == chptr)
273      {
# Line 304 | Line 286 | hash_del_channel(struct Channel *chptr)
286    }
287   }
288  
307 void
308 hash_del_resv(struct ResvChannel *chptr)
309 {
310  unsigned int hashv = strhash(chptr->name);
311  struct ResvChannel *tmp = resvchannelTable[hashv];
312
313  if (tmp != NULL)
314  {
315    if (tmp == chptr)
316    {
317      resvchannelTable[hashv] = chptr->hnext;
318      chptr->hnext = chptr;
319    }
320    else
321    {
322      while (tmp->hnext != chptr)
323        if ((tmp = tmp->hnext) == NULL)
324          return;
325
326      tmp->hnext = tmp->hnext->hnext;
327      chptr->hnext = chptr;
328    }
329  }
330 }
331
289   /* hash_find_client()
290   *
291   * inputs       - pointer to name
# Line 340 | Line 297 | hash_del_resv(struct ResvChannel *chptr)
297   struct Client *
298   hash_find_client(const char *name)
299   {
300 <  unsigned int hashv = strhash(name);
300 >  const unsigned int hashv = strhash(name);
301    struct Client *client_p;
302  
303 <  if ((client_p = clientTable[hashv]) != NULL)
303 >  if ((client_p = clientTable[hashv]))
304    {
305      if (irccmp(name, client_p->name))
306      {
307        struct Client *prev;
308  
309 <      while (prev = client_p, (client_p = client_p->hnext) != NULL)
309 >      while (prev = client_p, (client_p = client_p->hnext))
310        {
311          if (!irccmp(name, client_p->name))
312          {
# Line 368 | Line 325 | hash_find_client(const char *name)
325   struct Client *
326   hash_find_id(const char *name)
327   {
328 <  unsigned int hashv = strhash(name);
328 >  const unsigned int hashv = strhash(name);
329    struct Client *client_p;
330  
331 <  if ((client_p = idTable[hashv]) != NULL)
331 >  if ((client_p = idTable[hashv]))
332    {
333      if (strcmp(name, client_p->id))
334      {
335        struct Client *prev;
336  
337 <      while (prev = client_p, (client_p = client_p->idhnext) != NULL)
337 >      while (prev = client_p, (client_p = client_p->idhnext))
338        {
339          if (!strcmp(name, client_p->id))
340          {
# Line 396 | Line 353 | hash_find_id(const char *name)
353   struct Client *
354   hash_find_server(const char *name)
355   {
356 <  unsigned int hashv = strhash(name);
356 >  const unsigned int hashv = strhash(name);
357    struct Client *client_p = NULL;
358  
359    if (IsDigit(*name) && strlen(name) == IRC_MAXSID)
360      return hash_find_id(name);
361  
362 <  if ((client_p = clientTable[hashv]) != NULL)
362 >  if ((client_p = clientTable[hashv]))
363    {
364      if ((!IsServer(client_p) && !IsMe(client_p)) ||
365          irccmp(name, client_p->name))
366      {
367        struct Client *prev;
368  
369 <      while (prev = client_p, (client_p = client_p->hnext) != NULL)
369 >      while (prev = client_p, (client_p = client_p->hnext))
370        {
371          if ((IsServer(client_p) || IsMe(client_p)) &&
372              !irccmp(name, client_p->name))
# Line 430 | Line 387 | hash_find_server(const char *name)
387   *
388   * inputs       - pointer to name
389   * output       - NONE
390 < * side effects - New semantics: finds a channel whose name is 'name',
390 > * side effects - New semantics: finds a channel whose name is 'name',
391   *                if can't find one returns NULL, if can find it moves
392   *                it to the top of the list and returns it.
393   */
394   struct Channel *
395   hash_find_channel(const char *name)
396   {
397 <  unsigned int hashv = strhash(name);
397 >  const unsigned int hashv = strhash(name);
398    struct Channel *chptr = NULL;
399  
400 <  if ((chptr = channelTable[hashv]) != NULL)
400 >  if ((chptr = channelTable[hashv]))
401    {
402 <    if (irccmp(name, chptr->chname))
402 >    if (irccmp(name, chptr->name))
403      {
404        struct Channel *prev;
405  
406 <      while (prev = chptr, (chptr = chptr->hnextch) != NULL)
406 >      while (prev = chptr, (chptr = chptr->hnextch))
407        {
408 <        if (!irccmp(name, chptr->chname))
408 >        if (!irccmp(name, chptr->name))
409          {
410            prev->hnextch = chptr->hnextch;
411            chptr->hnextch = channelTable[hashv];
# Line 462 | Line 419 | hash_find_channel(const char *name)
419    return chptr;
420   }
421  
422 + struct UserHost *
423 + hash_find_userhost(const char *host)
424 + {
425 +  const unsigned int hashv = strhash(host);
426 +  struct UserHost *userhost;
427 +
428 +  if ((userhost = userhostTable[hashv]))
429 +  {
430 +    if (irccmp(host, userhost->host))
431 +    {
432 +      struct UserHost *prev;
433 +
434 +      while (prev = userhost, (userhost = userhost->next))
435 +      {
436 +        if (!irccmp(host, userhost->host))
437 +        {
438 +          prev->next = userhost->next;
439 +          userhost->next = userhostTable[hashv];
440 +          userhostTable[hashv] = userhost;
441 +          break;
442 +        }
443 +      }
444 +    }
445 +  }
446 +
447 +  return userhost;
448 + }
449 +
450   /* hash_get_bucket(int type, unsigned int hashv)
451   *
452   * inputs       - hash value (must be between 0 and HASHSIZE - 1)
# Line 476 | Line 461 | void *
461   hash_get_bucket(int type, unsigned int hashv)
462   {
463    assert(hashv < HASHSIZE);
464 +
465    if (hashv >= HASHSIZE)
466 <      return NULL;
466 >    return NULL;
467  
468    switch (type)
469    {
# Line 493 | Line 479 | hash_get_bucket(int type, unsigned int h
479      case HASH_TYPE_USERHOST:
480        return userhostTable[hashv];
481        break;
496    case HASH_TYPE_RESERVED:
497      return resvchannelTable[hashv];
498      break;
482      default:
483        assert(0);
484    }
# Line 503 | Line 486 | hash_get_bucket(int type, unsigned int h
486    return NULL;
487   }
488  
506 /* hash_find_resv()
507 *
508 * inputs       - pointer to name
509 * output       - NONE
510 * side effects - New semantics: finds a reserved channel whose name is 'name',
511 *                if can't find one returns NULL, if can find it moves
512 *                it to the top of the list and returns it.
513 */
514 struct ResvChannel *
515 hash_find_resv(const char *name)
516 {
517  unsigned int hashv = strhash(name);
518  struct ResvChannel *chptr;
519
520  if ((chptr = resvchannelTable[hashv]) != NULL)
521  {
522    if (irccmp(name, chptr->name))
523    {
524      struct ResvChannel *prev;
525
526      while (prev = chptr, (chptr = chptr->hnext) != NULL)
527      {
528        if (!irccmp(name, chptr->name))
529        {
530          prev->hnext = chptr->hnext;
531          chptr->hnext = resvchannelTable[hashv];
532          resvchannelTable[hashv] = chptr;
533          break;
534        }
535      }
536    }
537  }
538
539  return chptr;
540 }
541
542 struct UserHost *
543 hash_find_userhost(const char *host)
544 {
545  unsigned int hashv = strhash(host);
546  struct UserHost *userhost;
547
548  if ((userhost = userhostTable[hashv]))
549  {
550    if (irccmp(host, userhost->host))
551    {
552      struct UserHost *prev;
553
554      while (prev = userhost, (userhost = userhost->next) != NULL)
555      {
556        if (!irccmp(host, userhost->host))
557        {
558          prev->next = userhost->next;
559          userhost->next = userhostTable[hashv];
560          userhostTable[hashv] = userhost;
561          break;
562        }
563      }
564    }
565  }
566
567  return userhost;
568 }
569
570 /* count_user_host()
571 *
572 * inputs       - user name
573 *              - hostname
574 *              - int flag 1 if global, 0 if local
575 *              - pointer to where global count should go
576 *              - pointer to where local count should go
577 *              - pointer to where identd count should go (local clients only)
578 * output       - none
579 * side effects -
580 */
581 void
582 count_user_host(const char *user, const char *host, int *global_p,
583                int *local_p, int *icount_p)
584 {
585  dlink_node *ptr;
586  struct UserHost *found_userhost;
587  struct NameHost *nameh;
588
589  if ((found_userhost = hash_find_userhost(host)) == NULL)
590    return;
591
592  DLINK_FOREACH(ptr, found_userhost->list.head)
593  {
594    nameh = ptr->data;
595
596    if (!irccmp(user, nameh->name))
597    {
598      if (global_p != NULL)
599        *global_p = nameh->gcount;
600      if (local_p != NULL)
601        *local_p  = nameh->lcount;
602      if (icount_p != NULL)
603        *icount_p = nameh->icount;
604      return;
605    }
606  }
607 }
608
609 /* find_or_add_userhost()
610 *
611 * inputs       - host name
612 * output       - none
613 * side effects - find UserHost * for given host name
614 */
615 static struct UserHost *
616 find_or_add_userhost(const char *host)
617 {
618  struct UserHost *userhost;
619
620  if ((userhost = hash_find_userhost(host)) != NULL)
621    return userhost;
622
623  userhost = BlockHeapAlloc(userhost_heap);
624  strlcpy(userhost->host, host, sizeof(userhost->host));
625  hash_add_userhost(userhost);
626
627  return userhost;
628 }
629
630 /* add_user_host()
631 *
632 * inputs       - user name
633 *              - hostname
634 *              - int flag 1 if global, 0 if local
635 * output       - none
636 * side effects - add given user@host to hash tables
637 */
638 void
639 add_user_host(const char *user, const char *host, int global)
640 {
641  dlink_node *ptr;
642  struct UserHost *found_userhost;
643  struct NameHost *nameh;
644  int hasident = 1;
645
646  if (*user == '~')
647  {
648    hasident = 0;
649    ++user;
650  }
651
652  if ((found_userhost = find_or_add_userhost(host)) == NULL)
653    return;
654
655  DLINK_FOREACH(ptr, found_userhost->list.head)
656  {
657    nameh = ptr->data;
658
659    if (!irccmp(user, nameh->name))
660    {
661      nameh->gcount++;
662
663      if (!global)
664      {
665        if (hasident)
666          nameh->icount++;
667        nameh->lcount++;
668      }
669
670      return;
671    }
672  }
673
674  nameh = BlockHeapAlloc(namehost_heap);
675  strlcpy(nameh->name, user, sizeof(nameh->name));
676
677  nameh->gcount = 1;
678
679  if (!global)
680  {
681    if (hasident)
682      nameh->icount = 1;
683    nameh->lcount = 1;
684  }
685
686  dlinkAdd(nameh, &nameh->node, &found_userhost->list);
687 }
688
689 /* delete_user_host()
690 *
691 * inputs       - user name
692 *              - hostname
693 *              - int flag 1 if global, 0 if local
694 * output       - none
695 * side effects - delete given user@host to hash tables
696 */
697 void
698 delete_user_host(const char *user, const char *host, int global)
699 {
700  dlink_node *ptr = NULL, *next_ptr = NULL;
701  struct UserHost *found_userhost;
702  struct NameHost *nameh;
703  int hasident = 1;
704
705  if (*user == '~')
706  {
707    hasident = 0;
708    ++user;
709  }
710
711  if ((found_userhost = hash_find_userhost(host)) == NULL)
712    return;
713
714  DLINK_FOREACH_SAFE(ptr, next_ptr, found_userhost->list.head)
715  {
716    nameh = ptr->data;
717
718    if (!irccmp(user, nameh->name))
719    {
720      if (nameh->gcount > 0)
721        nameh->gcount--;
722      if (!global)
723      {
724        if (nameh->lcount > 0)
725          nameh->lcount--;
726        if (hasident && nameh->icount > 0)
727          nameh->icount--;
728      }
729
730      if (nameh->gcount == 0 && nameh->lcount == 0)
731      {
732        dlinkDelete(&nameh->node, &found_userhost->list);
733        BlockHeapFree(namehost_heap, nameh);
734      }
735
736      if (dlink_list_length(&found_userhost->list) == 0)
737      {
738        hash_del_userhost(found_userhost);
739        BlockHeapFree(userhost_heap, found_userhost);
740      }
741
742      return;
743    }
744  }
745 }
746
489   /*
490   * Safe list code.
491   *
# Line 767 | Line 509 | delete_user_host(const char *user, const
509   * Sendq limit is fairly conservative at 1/2 (In original anyway)
510   */
511   static int
512 < exceeding_sendq(struct Client *to)
512 > exceeding_sendq(const struct Client *to)
513   {
514 <  if (dbuf_length(&to->localClient->buf_sendq) > (get_sendq(to) / 2))
514 >  if (dbuf_length(&to->connection->buf_sendq) > (get_sendq(&to->connection->confs) / 2))
515      return 1;
516    else
517      return 0;
518   }
519  
520   void
521 < free_list_task(struct ListTask *lt, struct Client *source_p)
521 > free_list_task(struct Client *source_p)
522   {
523 <  dlink_node *dl, *dln;
523 >  struct ListTask *const lt = source_p->connection->list_task;
524 >  dlink_node *node = NULL, *node_next = NULL;
525  
526 <  if ((dl = dlinkFindDelete(&listing_client_list, source_p)) != NULL)
784 <    free_dlink_node(dl);
526 >  dlinkDelete(&lt->node, &listing_client_list);
527  
528 <  DLINK_FOREACH_SAFE(dl, dln, lt->show_mask.head)
528 >  DLINK_FOREACH_SAFE(node, node_next, lt->show_mask.head)
529    {
530 <    MyFree(dl->data);
531 <    free_dlink_node(dl);
530 >    xfree(node->data);
531 >    free_dlink_node(node);
532    }
533  
534 <  DLINK_FOREACH_SAFE(dl, dln, lt->hide_mask.head)
534 >  DLINK_FOREACH_SAFE(node, node_next, lt->hide_mask.head)
535    {
536 <    MyFree(dl->data);
537 <    free_dlink_node(dl);
536 >    xfree(node->data);
537 >    free_dlink_node(node);
538    }
539  
540 <  MyFree(lt);
541 <
800 <  if (MyConnect(source_p))
801 <    source_p->localClient->list_task = NULL;
540 >  xfree(lt);
541 >  source_p->connection->list_task = NULL;
542   }
543  
544   /* list_allow_channel()
# Line 810 | Line 550 | free_list_task(struct ListTask *lt, stru
550   * side effects -
551   */
552   static int
553 < list_allow_channel(const char *chname, struct ListTask *lt)
553 > list_allow_channel(const char *name, const struct ListTask *lt)
554   {
555 <  dlink_node *dl = NULL;
555 >  const dlink_node *node = NULL;
556  
557 <  DLINK_FOREACH(dl, lt->show_mask.head)
558 <    if (!match_chan(dl->data, chname))
557 >  DLINK_FOREACH(node, lt->show_mask.head)
558 >    if (match(node->data, name) != 0)
559        return 0;
560  
561 <  DLINK_FOREACH(dl, lt->hide_mask.head)
562 <    if (match_chan(dl->data, chname))
561 >  DLINK_FOREACH(node, lt->hide_mask.head)
562 >    if (match(node->data, name) == 0)
563        return 0;
564  
565    return 1;
# Line 834 | Line 574 | list_allow_channel(const char *chname, s
574   * side effects -
575   */
576   static void
577 < list_one_channel(struct Client *source_p, struct Channel *chptr,
838 <                 struct ListTask *list_task)
577 > list_one_channel(struct Client *source_p, struct Channel *chptr)
578   {
579 <  if (SecretChannel(chptr) && !IsMember(source_p, chptr))
579 >  const struct ListTask *const lt = source_p->connection->list_task;
580 >  char listbuf[MODEBUFLEN] = "";
581 >  char modebuf[MODEBUFLEN] = "";
582 >  char parabuf[MODEBUFLEN] = "";
583 >
584 >  if (SecretChannel(chptr) &&
585 >      !(HasUMode(source_p, UMODE_ADMIN) || IsMember(source_p, chptr)))
586      return;
587 <  if (dlink_list_length(&chptr->members) < list_task->users_min ||
588 <      dlink_list_length(&chptr->members) > list_task->users_max ||
589 <      (chptr->channelts != 0 &&
590 <       ((unsigned int)chptr->channelts < list_task->created_min ||
591 <        (unsigned int)chptr->channelts > list_task->created_max)) ||
592 <      (unsigned int)chptr->topic_time < list_task->topicts_min ||
587 >
588 >  if (dlink_list_length(&chptr->members) < lt->users_min ||
589 >      dlink_list_length(&chptr->members) > lt->users_max ||
590 >      (chptr->creationtime != 0 &&
591 >       ((unsigned int)chptr->creationtime < lt->created_min ||
592 >        (unsigned int)chptr->creationtime > lt->created_max)) ||
593 >      (unsigned int)chptr->topic_time < lt->topicts_min ||
594        (chptr->topic_time ? (unsigned int)chptr->topic_time : UINT_MAX) >
595 <      list_task->topicts_max)
595 >      lt->topicts_max)
596 >    return;
597 >
598 >  if (lt->topic[0] && match(lt->topic, chptr->topic))
599      return;
600  
601 <  if (!list_allow_channel(chptr->chname, list_task))
601 >  if (!list_allow_channel(chptr->name, lt))
602      return;
603 <  sendto_one(source_p, form_str(RPL_LIST), me.name, source_p->name,
604 <             chptr->chname, dlink_list_length(&chptr->members),
605 <             chptr->topic);
603 >
604 >  channel_modes(chptr, source_p, modebuf, parabuf);
605 >
606 >  if (chptr->topic[0])
607 >    snprintf(listbuf, sizeof(listbuf), "[%s] ", modebuf);
608 >  else
609 >    snprintf(listbuf, sizeof(listbuf), "[%s]",  modebuf);
610 >
611 >  sendto_one_numeric(source_p, &me, RPL_LIST, chptr->name,
612 >                     dlink_list_length(&chptr->members),
613 >                     listbuf, chptr->topic);
614   }
615  
616   /* safe_list_channels()
# Line 865 | Line 622 | list_one_channel(struct Client *source_p
622   * Walk the channel buckets, ensure all pointers in a bucket are
623   * traversed before blocking on a sendq. This means, no locking is needed.
624   *
868 * N.B. This code is "remote" safe, but is not currently used for
869 * remote clients.
870 *
625   * - Dianora
626   */
627   void
628 < safe_list_channels(struct Client *source_p, struct ListTask *list_task,
875 <                   int only_unmasked_channels)
628 > safe_list_channels(struct Client *source_p, int only_unmasked_channels)
629   {
630 +  struct ListTask *const lt = source_p->connection->list_task;
631    struct Channel *chptr = NULL;
632  
633    if (!only_unmasked_channels)
634    {
635 <    unsigned int i;
882 <
883 <    for (i = list_task->hash_index; i < HASHSIZE; ++i)
635 >    for (unsigned int i = lt->hash_index; i < HASHSIZE; ++i)
636      {
637 <      if (exceeding_sendq(source_p->from))
637 >      if (exceeding_sendq(source_p))
638        {
639 <        list_task->hash_index = i;
640 <        return;    /* still more to do */
639 >        lt->hash_index = i;
640 >        return;  /* Still more to do */
641        }
642  
643        for (chptr = channelTable[i]; chptr; chptr = chptr->hnextch)
644 <        list_one_channel(source_p, chptr, list_task);
644 >        list_one_channel(source_p, chptr);
645      }
646    }
647    else
648    {
649 <    dlink_node *dl;
649 >    dlink_node *node = NULL;
650  
651 <    DLINK_FOREACH(dl, list_task->show_mask.head)
652 <      if ((chptr = hash_find_channel(dl->data)) != NULL)
653 <        list_one_channel(source_p, chptr, list_task);
651 >    DLINK_FOREACH(node, lt->show_mask.head)
652 >      if ((chptr = hash_find_channel(node->data)))
653 >        list_one_channel(source_p, chptr);
654    }
655  
656 <  free_list_task(list_task, source_p);
657 <  sendto_one(source_p, form_str(RPL_LISTEND),
906 <             me.name, source_p->name);
656 >  free_list_task(source_p);
657 >  sendto_one_numeric(source_p, &me, RPL_LISTEND);
658   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)