]> jfr.im git - solanum.git/blobdiff - src/channel.c
Disallow $ in usernames as this may cause problems with ban forwarding.
[solanum.git] / src / channel.c
index 30f5583b65e2572eed4100e95fb2e5b55a05de82..1641a0e2b4c7088add67b00675c42765eb85c08a 100644 (file)
@@ -105,12 +105,13 @@ free_channel(struct Channel *chptr)
 }
 
 struct Ban *
-allocate_ban(const char *banstr, const char *who)
+allocate_ban(const char *banstr, const char *who, const char *forward)
 {
        struct Ban *bptr;
        bptr = rb_bh_alloc(ban_heap);
        bptr->banstr = rb_strdup(banstr);
        bptr->who = rb_strdup(who);
+       bptr->forward = forward ? rb_strdup(forward) : NULL;
 
        return (bptr);
 }
@@ -120,9 +121,31 @@ free_ban(struct Ban *bptr)
 {
        rb_free(bptr->banstr);
        rb_free(bptr->who);
+       rb_free(bptr->forward);
        rb_bh_free(ban_heap, bptr);
 }
 
+/*
+ * send_channel_join()
+ *
+ * input        - channel to join, client joining.
+ * output       - none
+ * side effects - none
+ */
+void
+send_channel_join(struct Channel *chptr, struct Client *client_p)
+{
+       if (!IsClient(client_p))
+               return;
+
+       sendto_channel_local_with_capability(ALL_MEMBERS, NOCAPS, CLICAP_EXTENDED_JOIN, chptr, ":%s!%s@%s JOIN %s",
+                                            client_p->name, client_p->username, client_p->host, chptr->chname);
+
+       sendto_channel_local_with_capability(ALL_MEMBERS, CLICAP_EXTENDED_JOIN, NOCAPS, chptr, ":%s!%s@%s JOIN %s %s :%s",
+                                            client_p->name, client_p->username, client_p->host, chptr->chname,
+                                            EmptyString(client_p->user->suser) ? "*" : client_p->user->suser,
+                                            client_p->info);
+}
 
 /* find_channel_membership()
  *
@@ -501,7 +524,7 @@ del_invite(struct Channel *chptr, struct Client *who)
  */
 int
 is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
-         const char *s, const char *s2)
+         const char *s, const char *s2, const char **forward)
 {
        char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
        char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
@@ -595,6 +618,9 @@ is_banned(struct Channel *chptr, struct Client *who, struct membership *msptr,
                }
        }
 
+       if (actualBan && actualBan->forward && forward)
+               *forward = actualBan->forward;
+
        return ((actualBan ? CHFL_BAN : 0));
 }
 
@@ -707,12 +733,12 @@ is_quieted(struct Channel *chptr, struct Client *who, struct membership *msptr,
 /* can_join()
  *
  * input       - client to check, channel to check for, key
- * output      - reason for not being able to join, else 0
+ * output      - reason for not being able to join, else 0, channel name to forward to
  * side effects -
  * caveats      - this function should only be called on a local user.
  */
 int
-can_join(struct Client *source_p, struct Channel *chptr, char *key)
+can_join(struct Client *source_p, struct Channel *chptr, char *key, char **forward)
 {
        rb_dlink_node *invite = NULL;
        rb_dlink_node *ptr;
@@ -749,12 +775,22 @@ can_join(struct Client *source_p, struct Channel *chptr, char *key)
                }
        }
 
-       if((is_banned(chptr, source_p, NULL, src_host, src_iphost)) == CHFL_BAN)
+       if((is_banned(chptr, source_p, NULL, src_host, src_iphost, forward)) == CHFL_BAN)
        {
                moduledata.approved = ERR_BANNEDFROMCHAN;
                goto finish_join_check;
        }
 
+       if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
+       {
+               moduledata.approved = ERR_BADCHANNELKEY;
+               goto finish_join_check;
+       }
+
+       /* All checks from this point on will forward... */
+       if(forward)
+               *forward = chptr->mode.forward;
+
        if(chptr->mode.mode & MODE_INVITEONLY)
        {
                RB_DLINK_FOREACH(invite, source_p->user->invited.head)
@@ -781,9 +817,6 @@ can_join(struct Client *source_p, struct Channel *chptr, char *key)
                }
        }
 
-       if(*chptr->mode.key && (EmptyString(key) || irccmp(chptr->mode.key, key)))
-               moduledata.approved = ERR_BADCHANNELKEY;
-
        if(chptr->mode.limit &&
           rb_dlink_list_length(&chptr->members) >= (unsigned long) chptr->mode.limit)
                i = ERR_CHANNELISFULL;
@@ -850,6 +883,8 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt
                                moduledata.approved = CAN_SEND_NO;
                        else
                                moduledata.approved = CAN_SEND_NONOP;
+
+                       return moduledata.approved;
                }
        }
 
@@ -864,7 +899,7 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt
                        if(can_send_banned(msptr))
                                moduledata.approved = CAN_SEND_NO;
                }
-               else if(is_banned(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN
+               else if(is_banned(chptr, source_p, msptr, NULL, NULL, NULL) == CHFL_BAN
                        || is_quieted(chptr, source_p, msptr, NULL, NULL) == CHFL_BAN)
                        moduledata.approved = CAN_SEND_NO;
        }
@@ -872,6 +907,11 @@ can_send(struct Channel *chptr, struct Client *source_p, struct membership *mspt
        if(is_chanop_voiced(msptr))
                moduledata.approved = CAN_SEND_OPV;
 
+       moduledata.client = source_p;
+       moduledata.chptr = msptr->chptr;
+       moduledata.msptr = msptr;
+       moduledata.target = NULL;
+
        call_hook(h_can_send, &moduledata);
 
        return moduledata.approved;
@@ -964,7 +1004,7 @@ find_bannickchange_channel(struct Client *client_p)
                        if (can_send_banned(msptr))
                                return chptr;
                }
-               else if (is_banned(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN
+               else if (is_banned(chptr, client_p, msptr, src_host, src_iphost, NULL) == CHFL_BAN
                        || is_quieted(chptr, client_p, msptr, src_host, src_iphost) == CHFL_BAN)
                        return chptr;
        }
@@ -1196,7 +1236,8 @@ channel_modes(struct Channel *chptr, struct Client *client_p)
                                           chptr->mode.join_time);
        }
 
-       if(*chptr->mode.forward && (ConfigChannel.use_forward || !IsClient(client_p)))
+       if(*chptr->mode.forward &&
+                       (ConfigChannel.use_forward || !IsClient(client_p)))
        {
                *mbuf++ = 'f';