]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/chanserv.c
small revert
[irc/evilnet/x3.git] / src / chanserv.c
index ef049886e19a008c4bdfc63b8d10a8b7bad0f066..a7bd7bf8827843f47e1e14416eb606ea2806e44b 100644 (file)
@@ -1638,25 +1638,43 @@ expire_channels(UNUSED_ARG(void *data))
 }
 
 static int
-protect_user(const struct userNode *victim, const struct userNode *aggressor, struct chanData *channel)
+protect_user(const struct userNode *victim, const struct userNode *aggressor, struct chanData *channel, int protect_invitables)
 {
     char protect = channel->chOpts[chProtect];
     struct userData *cs_victim, *cs_aggressor;
 
-    /* Don't protect if no one is to be protected, someone is attacking
-       himself, or if the aggressor is an IRC Operator. */
-    if(protect == 'n' || victim == aggressor /* Opers dont get special treatment :/  || IsOper(aggressor) */)
-       return 0;
+    /* If victim access level is greater than set invitelevel, don't let
+     * us kick them, but don't consider it punishment if someone else does
+     */
+
 
+    if(victim == aggressor)
+        return 0;
     /* Don't protect if the victim isn't authenticated (because they
        can't be a channel user), unless we are to protect non-users
        also. */
+
     cs_victim = GetChannelAccess(channel, victim->handle_info);
+
+    /* If they have enough access to invite themselvs through a ban,
+     * and its us kicking them, don't. -Rubin */
+    if(protect_invitables==true && cs_victim && (cs_victim->access >= channel->lvlOpts[lvlInviteMe]))
+        return 1;
+
+    if(protect == 'n')
+       return 0;
+
     if(protect != 'a' && !cs_victim)
         return 0;
 
     /* Protect if the aggressor isn't a user because at this point,
        the aggressor can only be less than or equal to the victim. */
+
+    /* Not protected from chanserv except above */
+    /* XXX: need to generic-ize chanserv to "one of x3's services" somehow.. */
+    if(aggressor == chanserv)
+        return 0;
+
     cs_aggressor = GetChannelAccess(channel, aggressor->handle_info);
     if(!cs_aggressor)
         return 1;
@@ -1728,7 +1746,7 @@ validate_deop(struct svccmd *cmd, struct userNode *user, struct chanNode *channe
        return 0;
     }
 
-    if(protect_user(victim, user, channel->channel_info))
+    if(protect_user(victim, user, channel->channel_info, false))
     {
        reply("CSMSG_USER_PROTECTED", victim->nick);
        return 0;
@@ -1746,7 +1764,7 @@ validate_dehop(struct svccmd *cmd, struct userNode *user, struct chanNode *chann
         return 0;
     }
 
-    if(protect_user(victim, user, channel->channel_info))
+    if(protect_user(victim, user, channel->channel_info, false))
     {
         reply("CSMSG_USER_PROTECTED", victim->nick);
         return 0;
@@ -2783,30 +2801,96 @@ static CHANSERV_FUNC(cmd_mdelowner)
 
 static CHANSERV_FUNC(cmd_mdelcoowner)
 {
-    return cmd_mdel_user(user, channel, UL_COOWNER, UL_COOWNER, argv[1], cmd);
+    return cmd_mdel_user(user, channel, UL_COOWNER, UL_OWNER-1, argv[1], cmd);
 }
 
 static CHANSERV_FUNC(cmd_mdelmanager)
 {
-    return cmd_mdel_user(user, channel, UL_MANAGER, UL_MANAGER, argv[1], cmd);
+    return cmd_mdel_user(user, channel, UL_MANAGER, UL_COOWNER-1, argv[1], cmd);
 }
 
 static CHANSERV_FUNC(cmd_mdelop)
 {
-    return cmd_mdel_user(user, channel, UL_OP, UL_OP, argv[1], cmd);
+    return cmd_mdel_user(user, channel, UL_OP, UL_MANAGER-1, argv[1], cmd);
 }
 
-static CHANSERV_FUNC(cmd_mdelpeon)
+static CHANSERV_FUNC(cmd_mdelhalfop)
 {
-    return cmd_mdel_user(user, channel, UL_PEON, UL_PEON, argv[1], cmd);
+    return cmd_mdel_user(user, channel, UL_HALFOP, UL_OP-1, argv[1], cmd);
 }
 
-static CHANSERV_FUNC(cmd_mdelhalfop)
+static CHANSERV_FUNC(cmd_mdelpeon)
 {
-    return cmd_mdel_user(user, channel, UL_HALFOP, UL_HALFOP, argv[1], cmd);
+    return cmd_mdel_user(user, channel, UL_PEON, UL_HALFOP-1, argv[1], cmd);
 }
 
 
+static CHANSERV_FUNC(cmd_levels)
+{
+    struct helpfile_table tbl;
+    int ii = 0;
+
+    tbl.length = 6 + 1; // 6 levels
+    tbl.width = 4;
+    tbl.flags = 0;
+    tbl.contents = calloc(tbl.length,sizeof(tbl.contents[0]));
+    tbl.contents[0] = calloc(tbl.width,sizeof(tbl.contents[0][0]));
+    tbl.contents[0][0] = "Level";
+    tbl.contents[0][1] = "From";
+    tbl.contents[0][2] = "-";
+    tbl.contents[0][3] = "To";
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_OWNER));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_OWNER);
+    tbl.contents[ii][2] = msnprintf(2, " ");
+    tbl.contents[ii][3] = msnprintf(1, "");
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_COOWNER));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_COOWNER);
+    tbl.contents[ii][2] = msnprintf(2, "-");
+    tbl.contents[ii][3] = msnprintf(4, "%d", UL_OWNER-1);
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_MANAGER));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_MANAGER);
+    tbl.contents[ii][2] = msnprintf(2, "-");
+    tbl.contents[ii][3] = msnprintf(4, "%d", UL_COOWNER-1);
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_OP));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_OP);
+    tbl.contents[ii][2] = msnprintf(2, "-");
+    tbl.contents[ii][3] = msnprintf(4, "%d", UL_MANAGER-1);
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_HALFOP));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_HALFOP);
+    tbl.contents[ii][2] = msnprintf(2, "-");
+    tbl.contents[ii][3] = msnprintf(4, "%d", UL_OP-1);
+
+    tbl.contents[++ii] = calloc(tbl.width, sizeof(tbl.contents[0][0]));
+    tbl.contents[ii][0] = strdup(user_level_name_from_level(UL_PEON));
+    tbl.contents[ii][1] = msnprintf(4, "%d", UL_PEON);
+    tbl.contents[ii][2] = msnprintf(2, "-");
+    tbl.contents[ii][3] = msnprintf(4, "%d", UL_HALFOP-1);
+
+    table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
+    return 0;
+
+/*
+    reply("CSMSG_LEVELS_HEADER");
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_OWNER), UL_OWNER, UL_OWNER);
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_COOWNER), UL_COOWNER, UL_OWNER-1);
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_MANAGER), UL_MANAGER, UL_COOWNER-1);
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_OP), UL_OP, UL_MANAGER-1);
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_HALFOP), UL_HALFOP, UL_OP-1);
+    reply("CSMSG_LEVELS",  user_level_name_from_level(UL_PEON), UL_PEON, UL_HALFOP-1);
+    reply("CSMSG_BAR");
+ */
+}
+
 /* trim_lamers.. */
 static int
 cmd_trim_bans(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, unsigned long duration)
@@ -3120,7 +3204,7 @@ bad_channel_ban(struct chanNode *channel, struct userNode *user, const char *ban
         if(!user_matches_glob(mn->user, ban, MATCH_USENICK | MATCH_VISIBLE))
             continue;
 
-        if(protect_user(mn->user, user, channel->channel_info))
+        if(protect_user(mn->user, user, channel->channel_info, false))
             return 1;
 
         if(victims)
@@ -3177,7 +3261,7 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
             return 0;
         }
 
-       if(protect_user(victim, user, channel->channel_info))
+       if(protect_user(victim, user, channel->channel_info, false))
        {
            // This translates to  send_message(user, cmd->parent->bot, ...)
            // if user is x3 (ctcp action) cmd is null and segfault.
@@ -3409,13 +3493,25 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
         }
     }
 
-    if(action & ACTION_KICK)
+    if(action & ACTION_ADD_LAMER)
     {
         char kick_reason[MAXLEN];
        sprintf(kick_reason, "(%s) %s", user->nick, reason);
 
-       for(n = 0; n < victimCount; n++)
+       for(n = 0; n < victimCount; n++) {
+            if(!protect_user(victims[n]->user, user, channel->channel_info, true)) {
+               KickChannelUser(victims[n]->user, channel, chanserv, kick_reason);
+            }
+        }
+    }
+    else if(action & ACTION_KICK)
+    {
+        char kick_reason[MAXLEN];
+       sprintf(kick_reason, "(%s) %s", user->nick, reason);
+
+       for(n = 0; n < victimCount; n++) {
            KickChannelUser(victims[n]->user, channel, chanserv, kick_reason);
+        }
     }
 
     if(!cmd)
@@ -3716,14 +3812,13 @@ static CHANSERV_FUNC(cmd_myaccess)
 
     if(argc < 2)
         target_handle = user->handle_info;
-    else if(!IsHelping(user))
+    else if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
+        return 0;
+    else if(!IsHelping(user) && target_handle != user->handle_info)
     {
         reply("CSMSG_MYACCESS_SELF_ONLY", argv[0]);
         return 0;
     }
-    else if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
-        return 0;
-
     if(!target_handle->channels)
     {
         reply("CSMSG_SQUAT_ACCESS", target_handle->handle);
@@ -7003,6 +7098,64 @@ handle_new_channel(struct chanNode *channel)
         SetChannelTopic(channel, chanserv, chanserv, channel->channel_info->topic, 1);
 }
 
+int
+check_bans(struct userNode *user, const char *channel)
+{
+    struct chanNode *chan;
+    struct mod_chanmode change;
+    struct chanData *cData;
+    struct banData *bData;
+
+    if (!(chan = GetChannel(channel)))
+        return 0;
+
+    if(!(cData = chan->channel_info))
+        return 0;
+
+    mod_chanmode_init(&change);
+    change.argc = 1;
+
+    if(chan->banlist.used < MAXBANS)
+    {
+        /* Not joining through a ban. */
+        for(bData = cData->bans;
+            bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
+            bData = bData->next);
+
+        if(bData)
+        {
+            char kick_reason[MAXLEN];
+            sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
+
+            bData->triggered = now;
+            if(bData != cData->bans)
+            {
+                /* Shuffle the ban to the head of the list. */
+                if(bData->next)
+                    bData->next->prev = bData->prev;
+                if(bData->prev)
+                    bData->prev->next = bData->next;
+
+                bData->prev = NULL;
+                bData->next = cData->bans;
+
+                if(cData->bans)
+                    cData->bans->prev = bData;
+                
+                cData->bans = bData;
+            }
+
+            change.args[0].mode = MODE_BAN;
+            change.args[0].u.hostmask = bData->mask;
+            mod_chanmode_announce(chanserv, chan, &change);
+            KickChannelUser(user, chan, chanserv, kick_reason);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+
 /* Welcome to my worst nightmare. Warning: Read (or modify)
    the code below at your own risk. */
 static int
@@ -7051,42 +7204,58 @@ handle_join(struct modeNode *mNode)
     }
 #endif
 
+    if(user->handle_info)
+    {
+        handle = user->handle_info;
+        if(handle)
+        {
+            uData = GetTrueChannelAccess(cData, handle);
+        }
+    }
+
+
     mod_chanmode_init(&change);
     change.argc = 1;
-    if(channel->banlist.used < MAXBANS)
-    {
-        /* Not joining through a ban. */
-        for(bData = cData->bans;
-            bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
-            bData = bData->next);
 
-        if(bData)
+    /* TODO: maybe only people above inviteme level? -Rubin */
+    /* We don't kick people with access */
+    if(!uData)
+    {
+        if(channel->banlist.used < MAXBANS)
         {
-            char kick_reason[MAXLEN];
-            sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
+            /* Not joining through a ban. */
+            for(bData = cData->bans;
+                bData && !user_matches_glob(user, bData->mask, MATCH_USENICK);
+                bData = bData->next);
 
-            bData->triggered = now;
-            if(bData != cData->bans)
+            if(bData)
             {
-                /* Shuffle the ban to the head of the list. */
-                if(bData->next)
-                    bData->next->prev = bData->prev;
-                if(bData->prev)
-                    bData->prev->next = bData->next;
+                char kick_reason[MAXLEN];
+                sprintf(kick_reason, "(%s) %s", bData->owner, bData->reason);
 
-                bData->prev = NULL;
-                bData->next = cData->bans;
+                bData->triggered = now;
+                if(bData != cData->bans)
+                {
+                    /* Shuffle the ban to the head of the list. */
+                    if(bData->next)
+                        bData->next->prev = bData->prev;
+                    if(bData->prev)
+                        bData->prev->next = bData->next;
+
+                    bData->prev = NULL;
+                    bData->next = cData->bans;
+
+                    if(cData->bans)
+                        cData->bans->prev = bData;
+                    cData->bans = bData;
+                }
 
-                if(cData->bans)
-                    cData->bans->prev = bData;
-                cData->bans = bData;
+                change.args[0].mode = MODE_BAN;
+                change.args[0].u.hostmask = bData->mask;
+                mod_chanmode_announce(chanserv, channel, &change);
+                KickChannelUser(user, channel, chanserv, kick_reason);
+                return 1;
             }
-
-            change.args[0].mode = MODE_BAN;
-            change.args[0].u.hostmask = bData->mask;
-            mod_chanmode_announce(chanserv, channel, &change);
-            KickChannelUser(user, channel, chanserv, kick_reason);
-            return 1;
         }
     }
 
@@ -7121,7 +7290,7 @@ handle_join(struct modeNode *mNode)
     greeting = cData->greeting;
     if(user->handle_info)
     {
-        handle = user->handle_info;
+/*        handle = user->handle_info; */
 
         if(IsHelper(user) && !IsHelping(user))
         {
@@ -7136,7 +7305,7 @@ handle_join(struct modeNode *mNode)
             }
         }
 
-        uData = GetTrueChannelAccess(cData, handle);
+/*        uData = GetTrueChannelAccess(cData, handle); */
         if(uData && !IsUserSuspended(uData))
         {
             /* non users getting automodes are handled above. */
@@ -7286,6 +7455,8 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
            || !channel->channel_info
            || IsSuspended(channel->channel_info))
             continue;
+        if(protect_user(user, chanserv, channel->channel_info, true))
+            continue;
         for(jj = 0; jj < channel->banlist.used; ++jj)
             if(user_matches_glob(user, channel->banlist.list[jj]->ban, MATCH_USENICK))
                 break;
@@ -7386,7 +7557,7 @@ handle_kick(struct userNode *kicker, struct userNode *victim, struct chanNode *c
        || (kicker->handle_info && kicker->handle_info == victim->handle_info))
         return;
 
-    if(protect_user(victim, kicker, channel->channel_info))
+    if(protect_user(victim, kicker, channel->channel_info, false))
     {
         const char *reason = user_find_message(kicker, "CSMSG_USER_PROTECTED_KICK");
        KickChannelUser(kicker, channel, chanserv, reason);
@@ -7462,7 +7633,7 @@ handle_mode(struct chanNode *channel, struct userNode *user, const struct mod_ch
         if((change->args[ii].mode & (MODE_REMOVE|MODE_CHANOP)) == (MODE_REMOVE|MODE_CHANOP))
         {
             const struct userNode *victim = change->args[ii].u.member->user;
-            if(!protect_user(victim, user, channel->channel_info))
+            if(!protect_user(victim, user, channel->channel_info, false))
                 continue;
             if(!bounce)
                 bounce = mod_chanmode_alloc(change->argc + 1 - ii);
@@ -7532,7 +7703,7 @@ handle_nick_change(struct userNode *user, UNUSED_ARG(const char *old_nick))
         /* Need not check for bans if they're opped or voiced. */
         /* TODO: does this make sense in automode v, h, and o? *
          * lets still enforce on voice people anyway, and see how that goes -Rubin */
-        if(user->channels.list[ii]->modes & (MODE_CHANOP|MODE_HALFOP /*|MODE_VOICE */))
+        if(user->channels.list[ii]->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE ))
             continue;
         /* Need not check for bans unless channel registration is active. */
         if(!channel->channel_info || IsSuspended(channel->channel_info))
@@ -7544,6 +7715,9 @@ handle_nick_change(struct userNode *user, UNUSED_ARG(const char *old_nick))
         /* Need not act if we found one. */
         if(jj < channel->banlist.used)
             continue;
+        /* don't kick someone on the userlist */
+        if(protect_user(user, chanserv, channel->channel_info, true))
+            continue;
         /* Look for a matching ban in this channel. */
         for(bData = channel->channel_info->bans; bData; bData = bData->next)
         {
@@ -8562,6 +8736,8 @@ init_chanserv(const char *nick)
     DEFINE_COMMAND(mdelpeon, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
     DEFINE_COMMAND(mdelhalfop, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
 
+    DEFINE_COMMAND(levels, 1, 0, NULL);
+
     DEFINE_COMMAND(trim, 3, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
     DEFINE_COMMAND(opchan, 1, MODCMD_REQUIRE_REGCHAN|MODCMD_NEVER_CSUSPEND, "access", "1", NULL);
     DEFINE_COMMAND(clvl, 3, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);