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

Comparing:
ircd-hybrid-7.2/src/channel.c (file contents), Revision 454 by michael, Sun Feb 12 19:01:25 2006 UTC vs.
ircd-hybrid-8/src/channel.c (file contents), Revision 1330 by michael, Sun Apr 1 12:12:00 2012 UTC

# Line 25 | Line 25
25   */
26  
27   #include "stdinc.h"
28 < #include "tools.h"
28 > #include "list.h"
29   #include "channel.h"
30   #include "channel_mode.h"
31   #include "client.h"
32 #include "common.h"
32   #include "hash.h"
33   #include "hostmask.h"
34   #include "irc_string.h"
35   #include "sprintf_irc.h"
36   #include "ircd.h"
38 #include "list.h"
37   #include "numeric.h"
38   #include "s_serv.h"             /* captab */
39   #include "s_user.h"
40   #include "send.h"
41 < #include "s_conf.h"             /* ConfigFileEntry, ConfigChannel */
41 > #include "conf.h"             /* ConfigFileEntry, ConfigChannel */
42   #include "event.h"
43   #include "memory.h"
44   #include "balloc.h"
45  
46   struct config_channel_entry ConfigChannel;
47   dlink_list global_channel_list = { NULL, NULL, 0 };
50 dlink_list lazylink_channels = { NULL, NULL, 0 };
48   BlockHeap *ban_heap;    /*! \todo ban_heap shouldn't be a global var */
49  
53 static BlockHeap *topic_heap = NULL;
50   static BlockHeap *member_heap = NULL;
51   static BlockHeap *channel_heap = NULL;
52  
# Line 64 | Line 60 | static char parabuf[MODEBUFLEN];
60   void
61   init_channels(void)
62   {
67  /*
68   * XXX - These should get moved to somwhere else once we have
69   * a modular channelmode system
70   */
63    add_capability("EX", CAP_EX, 1);
64    add_capability("IE", CAP_IE, 1);
65    add_capability("CHW", CAP_CHW, 1);
66  
67    channel_heap = BlockHeapCreate("channel", sizeof(struct Channel), CHANNEL_HEAP_SIZE);
68    ban_heap = BlockHeapCreate("ban", sizeof(struct Ban), BAN_HEAP_SIZE);
77  topic_heap = BlockHeapCreate("topic", TOPICLEN+1 + USERHOST_REPLYLEN, TOPIC_HEAP_SIZE);
69    member_heap = BlockHeapCreate("member", sizeof(struct Membership), CHANNEL_HEAP_SIZE*2);
70   }
71  
# Line 128 | Line 119 | add_user_to_channel(struct Channel *chpt
119    ms->flags = flags;
120  
121    dlinkAdd(ms, &ms->channode, &chptr->members);
131
132  if (MyConnect(who))
133    dlinkAdd(ms, &ms->locchannode, &chptr->locmembers);
134
122    dlinkAdd(ms, &ms->usernode, &who->channel);
123   }
124  
# Line 146 | Line 133 | remove_user_from_channel(struct Membersh
133    struct Channel *chptr = member->chptr;
134  
135    dlinkDelete(&member->channode, &chptr->members);
149
150  if (MyConnect(client_p))
151    dlinkDelete(&member->locchannode, &chptr->locmembers);
152
136    dlinkDelete(&member->usernode, &client_p->channel);
137  
138    BlockHeapFree(member_heap, member);
139  
140 <  if (dlink_list_length(&chptr->members) == 0)
158 <  {
159 <    assert(dlink_list_length(&chptr->locmembers) == 0);
140 >  if (chptr->members.head == NULL)
141      destroy_channel(chptr);
161  }
142   }
143  
144   /* send_members()
# Line 200 | Line 180 | send_members(struct Client *client_p, st
180      /* space will be converted into CR, but we also need space for LF..
181       * That's why we use '- 1' here
182       * -adx */
183 <    if (t + tlen - buf > sizeof(buf) - 1)
183 >    if (t + tlen - buf > IRCD_BUFSIZE - 1)
184      {
185        *(t - 1) = '\0';  /* kill the space and terminate the string */
186        sendto_one(client_p, "%s", buf);
# Line 323 | Line 303 | send_channel_modes(struct Client *client
303  
304   /*! \brief check channel name for invalid characters
305   * \param name pointer to channel name string
306 < * \return TRUE (1) if name ok, FALSE (0) otherwise
306 > * \param local indicates whether it's a local or remote creation
307 > * \return 0 if invalid, 1 otherwise
308   */
309   int
310 < check_channel_name(const char *name)
310 > check_channel_name(const char *name, int local)
311   {
312 <  const unsigned char *p = (const unsigned char *)name;
312 >  const char *p = name;
313 >  int max_length = local ? LOCAL_CHANNELLEN : CHANNELLEN;
314    assert(name != NULL);
315  
316 <  for (; *p; ++p)
317 <    if (!IsChanChar(*p))
318 <      return 0;
316 >  if (!IsChanPrefix(*p))
317 >    return 0;
318 >
319 >  if (!local || !ConfigChannel.disable_fake_channels)
320 >  {
321 >    while (*++p)
322 >      if (!IsChanChar(*p))
323 >        return 0;
324 >  }
325 >  else
326 >  {
327 >    while (*++p)
328 >      if (!IsVisibleChanChar(*p))
329 >        return 0;
330 >  }
331  
332 <  return 1;
332 >  return p - name <= max_length;
333   }
334  
335   void
# Line 370 | Line 364 | free_channel_list(dlink_list *list)
364  
365   /*! \brief Get Channel block for chname (and allocate a new channel
366   *         block, if it didn't exist before)
367 < * \param client_p client pointer
368 < * \param chname   channel name
375 < * \param isnew    pointer to int flag whether channel was newly created or not
376 < * \return channel block or NULL if illegal name
367 > * \param chname channel name
368 > * \return channel block
369   */
370   struct Channel *
371 < get_or_create_channel(struct Client *client_p, const char *chname, int *isnew)
371 > make_channel(const char *chname)
372   {
373    struct Channel *chptr = NULL;
382  int len;
374  
375 <  if (EmptyString(chname))
385 <    return NULL;
386 <
387 <  if ((len = strlen(chname)) > CHANNELLEN)
388 <  {
389 <    if (IsServer(client_p))
390 <      sendto_realops_flags(UMODE_DEBUG, L_ALL,
391 <                           "*** Long channel name from %s (%d > %d): %s",
392 <                           client_p->name, len, CHANNELLEN, chname);
393 <    return NULL;
394 <  }
395 <
396 <  if ((chptr = hash_find_channel(chname)) != NULL)
397 <  {
398 <    if (isnew != NULL)
399 <      *isnew = 0;
400 <
401 <    return chptr;
402 <  }
403 <
404 <  if (isnew != NULL)
405 <    *isnew = 1;
375 >  assert(!EmptyString(chname));
376  
377    chptr = BlockHeapAlloc(channel_heap);
378 +
379    /* doesn't hurt to set it here */
380 <  chptr->channelts = chptr->last_join_time = CurrentTime;
380 >  chptr->channelts = CurrentTime;
381 >  chptr->last_join_time = CurrentTime;
382  
383    strlcpy(chptr->chname, chname, sizeof(chptr->chname));
384    dlinkAdd(chptr, &chptr->node, &global_channel_list);
# Line 432 | Line 404 | destroy_channel(struct Channel *chptr)
404    free_channel_list(&chptr->exceptlist);
405    free_channel_list(&chptr->invexlist);
406  
435  /* Free the topic */
436  free_topic(chptr);
437
407    dlinkDelete(&chptr->node, &global_channel_list);
408    hash_del_channel(chptr);
409  
441  if (ServerInfo.hub)
442    if ((ptr = dlinkFindDelete(&lazylink_channels, chptr)))
443      free_dlink_node(ptr);
444
410    BlockHeapFree(channel_heap, chptr);
411   }
412  
# Line 450 | Line 415 | destroy_channel(struct Channel *chptr)
415   * \return string pointer "=" if public, "@" if secret else "*"
416   */
417   static const char *
418 < channel_pub_or_secret(struct Channel *chptr)
418 > channel_pub_or_secret(const struct Channel *chptr)
419   {
420    if (SecretChannel(chptr))
421      return "@";
# Line 476 | Line 441 | channel_member_names(struct Client *sour
441    char *t = NULL, *start = NULL;
442    int tlen = 0;
443    int is_member = IsMember(source_p, chptr);
444 +  int multi_prefix = HasCap(source_p, CAP_MULTI_PREFIX) != 0;
445  
446    if (PubChannel(chptr) || is_member)
447    {
# Line 490 | Line 456 | channel_member_names(struct Client *sour
456        ms       = ptr->data;
457        target_p = ms->client_p;
458  
459 <      if (IsInvisible(target_p) && !is_member)
459 >      if (HasUMode(target_p, UMODE_INVISIBLE) && !is_member)
460          continue;
461  
462        tlen = strlen(target_p->name) + 1;  /* nick + space */
463  
464 <      if (ms->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
465 <        ++tlen;
466 <      if (t + tlen - lbuf > IRCD_BUFSIZE)
464 >      if (!multi_prefix)
465 >      {
466 >        if (ms->flags & (CHFL_CHANOP | CHFL_HALFOP | CHFL_VOICE))
467 >          ++tlen;
468 >      }
469 >      else
470 >      {
471 >        if (ms->flags & CHFL_CHANOP)
472 >          ++tlen;
473 >        if (ms->flags & CHFL_HALFOP)
474 >          ++tlen;
475 >        if (ms->flags & CHFL_VOICE)
476 >          ++tlen;
477 >      }
478 >
479 >      if (t + tlen - lbuf > IRCD_BUFSIZE - 2)
480        {
481          *(t - 1) = '\0';
482          sendto_one(source_p, "%s", lbuf);
483          t = start;
484        }
485  
486 <      t += ircsprintf(t, "%s%s ", get_member_status(ms, NO),
486 >      t += ircsprintf(t, "%s%s ", get_member_status(ms, multi_prefix),
487                        target_p->name);
488      }
489  
# Line 654 | Line 633 | find_bmask(const struct Client *who, con
633   * \return 0 if not banned, 1 otherwise
634   */
635   int
636 < is_banned(struct Channel *chptr, struct Client *who)
636 > is_banned(const struct Channel *chptr, const struct Client *who)
637   {
638 <  assert(IsClient(who));
638 >  if (find_bmask(who, &chptr->banlist))
639 >    if (!ConfigChannel.use_except || !find_bmask(who, &chptr->exceptlist))
640 >      return 1;
641  
642 <  return find_bmask(who, &chptr->banlist) && (!ConfigChannel.use_except ||
662 <         !find_bmask(who, &chptr->exceptlist));
642 >  return 0;
643   }
644  
645   /*!
# Line 672 | Line 652 | is_banned(struct Channel *chptr, struct
652   int
653   can_join(struct Client *source_p, struct Channel *chptr, const char *key)
654   {
655 <  if (find_bmask(source_p, &chptr->banlist))
656 <    if (!ConfigChannel.use_except || !find_bmask(source_p, &chptr->exceptlist))
657 <      return ERR_BANNEDFROMCHAN;
655 >  if (is_banned(chptr, source_p))
656 >    return ERR_BANNEDFROMCHAN;
657 >
658 > #ifdef HAVE_LIBCRYPTO
659 >  if ((chptr->mode.mode & MODE_SSLONLY) && !source_p->localClient->fd.ssl)
660 >    return ERR_SSLONLYCHAN;
661 > #endif
662 >
663 >  if ((chptr->mode.mode & MODE_REGONLY) && !HasUMode(source_p, UMODE_REGISTERED))
664 >    return ERR_NEEDREGGEDNICK;
665 >
666 >  if ((chptr->mode.mode & MODE_OPERONLY) && !HasUMode(source_p, UMODE_OPER))
667 >    return ERR_OPERONLYCHAN;
668  
669    if (chptr->mode.mode & MODE_INVITEONLY)
670      if (!dlinkFind(&source_p->localClient->invited, chptr))
671        if (!ConfigChannel.use_invex || !find_bmask(source_p, &chptr->invexlist))
672          return ERR_INVITEONLYCHAN;
673  
674 <  if (chptr->mode.key[0] && (EmptyString(key) || irccmp(chptr->mode.key, key)))
674 >  if (chptr->mode.key[0] && (!key || irccmp(chptr->mode.key, key)))
675      return ERR_BADCHANNELKEY;
676  
677    if (chptr->mode.limit && dlink_list_length(&chptr->members) >=
# Line 709 | Line 699 | find_channel_link(struct Client *client_
699  
700    DLINK_FOREACH(ptr, client_p->channel.head)
701      if (((struct Membership *)ptr->data)->chptr == chptr)
702 <      return (struct Membership *)ptr->data;
702 >      return ptr->data;
703  
704    return NULL;
705   }
# Line 720 | Line 710 | find_channel_link(struct Client *client_
710   * \param ms       pointer to Membership struct (can be NULL)
711   * \return CAN_SEND_OPV if op or voiced on channel\n
712   *         CAN_SEND_NONOP if can send to channel but is not an op\n
713 < *         CAN_SEND_NO if they cannot send to channel\n
713 > *         ERR_CANNOTSENDTOCHAN or ERR_NEEDREGGEDNICK if they cannot send to channel\n
714   */
715   int
716   can_send(struct Channel *chptr, struct Client *source_p, struct Membership *ms)
717   {
718 <  if (IsServer(source_p))
718 >  if (IsServer(source_p) || HasFlag(source_p, FLAGS_SERVICE))
719      return CAN_SEND_OPV;
720  
721 <  if (MyClient(source_p) && !IsExemptResv(source_p) &&
722 <      !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv) &&
723 <      (!hash_find_resv(chptr->chname) == ConfigChannel.restrict_channels))
724 <    return CAN_SEND_NO;
721 >  if (MyClient(source_p) && !IsExemptResv(source_p))
722 >    if (!(HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.oper_pass_resv))
723 >      if (!hash_find_resv(chptr->chname) == ConfigChannel.restrict_channels)
724 >        return ERR_CANNOTSENDTOCHAN;
725  
726    if (ms != NULL || (ms = find_channel_link(source_p, chptr)))
727    {
# Line 742 | Line 732 | can_send(struct Channel *chptr, struct C
732      if (ConfigChannel.quiet_on_ban && MyClient(source_p))
733      {
734        if (ms->flags & CHFL_BAN_SILENCED)
735 <        return CAN_SEND_NO;
735 >        return ERR_CANNOTSENDTOCHAN;
736  
737        if (!(ms->flags & CHFL_BAN_CHECKED))
738        {
739          if (is_banned(chptr, source_p))
740          {
741            ms->flags |= (CHFL_BAN_CHECKED|CHFL_BAN_SILENCED);
742 <          return CAN_SEND_NO;
742 >          return ERR_CANNOTSENDTOCHAN;
743          }
744  
745          ms->flags |= CHFL_BAN_CHECKED;
746        }
747      }
748    }
749 +  else if (chptr->mode.mode & MODE_NOPRIVMSGS)
750 +    return ERR_CANNOTSENDTOCHAN;
751  
752 <  if (chptr->mode.mode & (MODE_MODERATED|MODE_NOPRIVMSGS))
753 <    return CAN_SEND_NO;
752 >  if (chptr->mode.mode & MODE_MODERATED)
753 >    return ERR_CANNOTSENDTOCHAN;
754  
755    return CAN_SEND_NONOP;
756   }
# Line 859 | Line 851 | check_splitmode(void *unused)
851    }
852   }
853  
862 /*! \brief Allocates a new topic
863 * \param chptr Channel to allocate a new topic for
864 */
865 static void
866 allocate_topic(struct Channel *chptr)
867 {
868  void *ptr = NULL;
869
870  if (chptr == NULL)
871    return;
872
873  ptr = BlockHeapAlloc(topic_heap);  
874
875  /* Basically we allocate one large block for the topic and
876   * the topic info.  We then split it up into two and shove it
877   * in the chptr
878   */
879  chptr->topic       = ptr;
880  chptr->topic_info  = (char *)ptr + TOPICLEN+1;
881  *chptr->topic      = '\0';
882  *chptr->topic_info = '\0';
883 }
884
885 void
886 free_topic(struct Channel *chptr)
887 {
888  void *ptr = NULL;
889  assert(chptr);
890  if (chptr->topic == NULL)
891    return;
892
893  /*
894   * If you change allocate_topic you MUST change this as well
895   */
896  ptr = chptr->topic;
897  BlockHeapFree(topic_heap, ptr);    
898  chptr->topic      = NULL;
899  chptr->topic_info = NULL;
900 }
901
854   /*! \brief Sets the channel topic for chptr
855   * \param chptr      Pointer to struct Channel
856   * \param topic      The topic string
# Line 909 | Line 861 | void
861   set_channel_topic(struct Channel *chptr, const char *topic,
862                    const char *topic_info, time_t topicts)
863   {
864 <  if (!EmptyString(topic))
865 <  {
866 <    if (chptr->topic == NULL)
915 <      allocate_topic(chptr);
916 <
917 <    strlcpy(chptr->topic, topic, TOPICLEN+1);
918 <    strlcpy(chptr->topic_info, topic_info, USERHOST_REPLYLEN);
919 <    chptr->topic_time = topicts;
920 <  }
921 <  else
922 <  {
923 <    /*
924 <     * Do not reset chptr->topic_time here, it's required for
925 <     * bursting topics properly.
926 <     */
927 <    if (chptr->topic != NULL)
928 <      free_topic(chptr);
929 <  }
864 >  strlcpy(chptr->topic, topic, sizeof(chptr->topic));
865 >  strlcpy(chptr->topic_info, topic_info, sizeof(chptr->topic_info));
866 >  chptr->topic_time = topicts;
867   }

Diff Legend

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