ChanServ seen fixes; other cleanups
[srvx.git] / src / chanserv.c
index dcdb6316dfc414c3e767a66123013bba64d75df2..8ad057af26ba089d123e4f2c041adbf4321582b4 100644 (file)
@@ -1,11 +1,12 @@
 /* chanserv.c - Channel service bot
  * Copyright 2000-2004 srvx Development Team
  *
- * This program is free software; you can redistribute it and/or modify
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.  Important limitations are
- * listed in the COPYING file that accompanies this software.
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,7 +14,8 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, email srvx-maintainers@srvx.net.
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
  */
 
 #include "chanserv.h"
@@ -180,7 +182,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_DELETED_YOU", "Your $b%d$b access has been deleted from $b%s$b." },
 
 /* User management */
-    { "CSMSG_ADDED_USER", "Added new %s to the %s user list with access %d." },
+    { "CSMSG_ADDED_USER", "Added %s to the %s user list with access %d." },
     { "CSMSG_DELETED_USER", "Deleted %s (with access %d) from the %s user list." },
     { "CSMSG_BAD_RANGE", "Invalid access range; minimum (%d) must be greater than maximum (%d)." },
     { "CSMSG_DELETED_USERS", "Deleted accounts matching $b%s$b with access from $b%d$b to $b%d$b from the %s user list." },
@@ -1238,8 +1240,7 @@ expire_ban(void *data)
         struct mod_chanmode change;
         unsigned int ii;
         bans = bd->channel->channel->banlist;
-        change.modes_set = change.modes_clear = 0;
-        change.argc = 0;
+        mod_chanmode_init(&change);
         for(ii=0; ii<bans.used; ii++)
         {
             if(!strcmp(bans.list[ii]->ban, bd->mask))
@@ -1880,7 +1881,7 @@ static CHANSERV_FUNC(cmd_move)
     else if(!IsSuspended(channel->channel_info))
     {
         struct mod_chanmode change;
-        change.modes_set = change.modes_clear = 0;
+        mod_chanmode_init(&change);
         change.argc = 1;
         change.args[0].mode = MODE_CHANOP;
         change.args[0].member = AddChannelUser(chanserv, target);
@@ -2142,7 +2143,7 @@ static CHANSERV_FUNC(cmd_opchan)
         return 0;
     }
     channel->channel_info->may_opchan = 0;
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].mode = MODE_CHANOP;
     change.args[0].member = GetUserMode(channel, chanserv);
@@ -2480,7 +2481,7 @@ static CHANSERV_FUNC(cmd_up)
     struct userData *uData;
     const char *errmsg;
 
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].member = GetUserMode(channel, user);
     if(!change.args[0].member)
@@ -2522,7 +2523,7 @@ static CHANSERV_FUNC(cmd_down)
 {
     struct mod_chanmode change;
 
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].member = GetUserMode(channel, user);
     if(!change.args[0].member)
@@ -3541,6 +3542,8 @@ static CHANSERV_FUNC(cmd_bans)
     {
         table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
        reply("MSG_NONE");
+        free(tbl.contents[0]);
+        free(tbl.contents);
        return 0;
     }
 
@@ -4033,19 +4036,22 @@ static CHANSERV_FUNC(cmd_resync)
     {
         struct modeNode *mn = channel->members.list[ii];
         struct userData *uData;
+
         if(IsService(mn->user))
+            continue;
+
+        uData = GetChannelAccess(cData, mn->user->handle_info);
+        if(!cData->lvlOpts[lvlGiveOps]
+           || (uData && uData->access >= cData->lvlOpts[lvlGiveOps]))
         {
-            /* must not change modes for this user */
-        }
-        else if(!(uData = GetChannelAccess(cData, mn->user->handle_info)))
-        {
-            if(mn->modes)
+            if(!(mn->modes & MODE_CHANOP))
             {
-                changes->args[used].mode = MODE_REMOVE | mn->modes;
+                changes->args[used].mode = MODE_CHANOP;
                 changes->args[used++].member = mn;
             }
         }
-        else if(uData->access < cData->lvlOpts[lvlGiveOps])
+        else if(!cData->lvlOpts[lvlGiveVoice]
+                || (uData && uData->access >= cData->lvlOpts[lvlGiveVoice]))
         {
             if(mn->modes & MODE_CHANOP)
             {
@@ -4060,9 +4066,9 @@ static CHANSERV_FUNC(cmd_resync)
         }
         else
         {
-            if(!(mn->modes & MODE_CHANOP))
+            if(mn->modes)
             {
-                changes->args[used].mode = MODE_CHANOP;
+                changes->args[used].mode = MODE_REMOVE | mn->modes;
                 changes->args[used++].member = mn;
             }
         }
@@ -4318,11 +4324,11 @@ static CHANSERV_FUNC(cmd_say)
     {
         REQUIRE_PARAMS(3);
         msg = unsplit_string(argv + 2, argc - 2, NULL);
-        send_target_message(1, argv[1], cmd->parent->bot, "%s", msg);
+        send_target_message(5, argv[1], cmd->parent->bot, "%s", msg);
     }
     else
     {
-        reply("You must specify the name of a channel or user.");
+        reply("MSG_NOT_TARGET_NAME");
         return 0;
     }
     return 1;
@@ -4341,11 +4347,11 @@ static CHANSERV_FUNC(cmd_emote)
     else if(GetUserH(argv[1]))
     {
         msg = unsplit_string(argv + 2, argc - 2, NULL);
-        send_target_message(1, argv[1], cmd->parent->bot, "\001ACTION %s\001", msg);
+        send_target_message(5, argv[1], cmd->parent->bot, "\001ACTION %s\001", msg);
     }
     else
     {
-        reply("You must specify the name of a channel or user.");
+        reply("MSG_NOT_TARGET_NAME");
         return 0;
     }
     return 1;
@@ -4377,7 +4383,7 @@ chanserv_expire_suspension(void *data)
     channel = suspended->cData->channel;
     suspended->cData->channel = channel;
     suspended->cData->flags &= ~CHANNEL_SUSPENDED;
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].mode = MODE_CHANOP;
     change.args[0].member = AddChannelUser(chanserv, channel);
@@ -4884,35 +4890,6 @@ static MODCMD_FUNC(chan_opt_dynlimit)
     CHANNEL_BINARY_OPTION("CSMSG_SET_DYNLIMIT", CHANNEL_DYNAMIC_LIMIT);
 }
 
-/* TODO: reimplement
-
-static MODCMD_FUNC(chan_opt_userinfo)
-{
-    CHANNEL_BINARY_OPTION("CSMSG_SET_USERINFO", CHANNEL_INFO_LINES);
-}
-
-static MODCMD_FUNC(chan_opt_voice)
-{
-    CHANNEL_BINARY_OPTION("CSMSG_SET_VOICE", CHANNEL_VOICE_ALL);
-}
-
-static MODCMD_FUNC(chan_opt_topicsnarf)
-{
-    if((argc > 0) && !check_user_level(channel, user, lvlEnfTopic, 1, 0))
-    {
-        reply("CSMSG_TOPIC_LOCKED", channel->name);
-        return 0;
-    }
-    CHANNEL_BINARY_OPTION("CSMSG_SET_TOPICSNARF", CHANNEL_TOPIC_SNARF);
-}
-
-static MODCMD_FUNC(chan_opt_peoninvite)
-{
-    CHANNEL_BINARY_OPTION("CSMSG_SET_PEONINVITE", CHANNEL_PEON_INVITE);
-}
-
-*/
-
 static MODCMD_FUNC(chan_opt_defaults)
 {
     struct userData *uData;
@@ -5642,20 +5619,11 @@ static CHANSERV_FUNC(cmd_d)
 
 static CHANSERV_FUNC(cmd_huggle)
 {
-    char response[MAXLEN];
-    const char *fmt;
     /* CTCP must be via PRIVMSG, never notice */
     if(channel)
-    {
-        fmt = user_find_message(user, "CSMSG_HUGGLES_HIM");
-        sprintf(response, fmt, user->nick);
-        irc_privmsg(cmd->parent->bot, channel->name, response);
-    }
+        send_target_message(1, channel->name, cmd->parent->bot, "CSMSG_HUGGLES_HIM", user->nick);
     else
-    {
-        fmt = user_find_message(user, "CSMSG_HUGGLES_YOU");
-        irc_privmsg(cmd->parent->bot, user->nick, fmt);
-    }
+        send_target_message(1, user->nick, cmd->parent->bot, "CSMSG_HUGGLES_YOU");
     return 1;
 }
 
@@ -5680,10 +5648,9 @@ chanserv_adjust_limit(void *data)
             return;
     }
 
+    mod_chanmode_init(&change);
     change.modes_set = MODE_LIMIT;
-    change.modes_clear = 0;
     change.new_limit = limit;
-    change.argc = 0;
     mod_chanmode_announce(chanserv, channel, &change);
 }
 
@@ -5748,7 +5715,7 @@ handle_join(struct modeNode *mNode)
         }
     }
 
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     if(channel->banlist.used < MAXBANS)
     {
@@ -5766,8 +5733,10 @@ handle_join(struct modeNode *mNode)
             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;
+                if(bData->next)
+                    bData->next->prev = bData->prev;
+                if(bData->prev)
+                    bData->prev->next = bData->next;
 
                 bData->prev = NULL;
                 bData->next = cData->bans;
@@ -5881,7 +5850,7 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
     if(!user->handle_info)
        return;
 
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     for(channel = user->handle_info->channels; channel; channel = channel->u_next)
     {
@@ -5987,7 +5956,10 @@ handle_part(struct userNode *user, struct chanNode *channel, UNUSED_ARG(const ch
     }
 
     if((uData = GetTrueChannelAccess(cData, user->handle_info)))
+    {
        scan_user_presence(uData, user);
+        uData->seen = now;
+    }
 
     if(IsHelping(user) && IsSupportHelper(user))
     {
@@ -6008,6 +5980,8 @@ handle_part(struct userNode *user, struct chanNode *channel, UNUSED_ARG(const ch
 static void
 handle_kick(struct userNode *kicker, struct userNode *victim, struct chanNode *channel)
 {
+    struct userData *uData;
+
     if(!channel->channel_info || !kicker || IsService(kicker)
        || (kicker == victim) || IsSuspended(channel->channel_info)
        || (kicker->handle_info && kicker->handle_info == victim->handle_info))
@@ -6018,6 +5992,9 @@ handle_kick(struct userNode *kicker, struct userNode *victim, struct chanNode *c
         const char *reason = user_find_message(kicker, "CSMSG_USER_PROTECTED");
        KickChannelUser(kicker, channel, chanserv, reason);
     }
+
+    if((uData = GetTrueChannelAccess(channel->channel_info, victim->handle_info)))
+        uData->seen = now;
 }
 
 static int
@@ -6061,8 +6038,7 @@ handle_mode(struct chanNode *channel, struct userNode *user, const struct mod_ch
        && mode_lock_violated(&channel->channel_info->modes, change))
     {
         char correct[MAXLEN];
-        bounce = mod_chanmode_alloc(change->argc + 1);
-        *bounce = channel->channel_info->modes;
+        bounce = mod_chanmode_dup(&channel->channel_info->modes, change->argc + 1);
         mod_chanmode_format(&channel->channel_info->modes, correct);
         send_message(user, chanserv, "CSMSG_MODE_LOCKED", correct, channel->name);
     }
@@ -6129,7 +6105,7 @@ handle_nick_change(struct userNode *user, UNUSED_ARG(const char *old_nick))
     unsigned int ii, jj;
     char kick_reason[MAXLEN];
 
-    change.modes_set = change.modes_clear = 0;
+    mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].mode = MODE_BAN;
     for(ii = 0; ii < user->channels.used; ++ii)
@@ -6627,7 +6603,7 @@ chanserv_channel_read(const char *key, struct record_data *hir)
     if(!(cData->flags & CHANNEL_SUSPENDED))
     {
         struct mod_chanmode change;
-        change.modes_set = change.modes_clear = 0;
+        mod_chanmode_init(&change);
         change.argc = 1;
         change.args[0].mode = MODE_CHANOP;
         change.args[0].member = AddChannelUser(chanserv, cNode);
@@ -7045,7 +7021,7 @@ init_chanserv(const char *nick)
     DEFINE_COMMAND(mdelpeon, 2, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
 
     DEFINE_COMMAND(trim, 3, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
-    DEFINE_COMMAND(opchan, 1, MODCMD_REQUIRE_REGCHAN, "access", "1", NULL);
+    DEFINE_COMMAND(opchan, 1, MODCMD_REQUIRE_REGCHAN|MODCMD_NEVER_CSUSPEND, "access", "1", NULL);
     DEFINE_COMMAND(clvl, 3, MODCMD_REQUIRE_CHANUSER, "access", "master", NULL);
     DEFINE_COMMAND(giveownership, 2, MODCMD_REQUIRE_CHANUSER, "access", "owner", "flags", "+loghostmask", NULL);