License update
[srvx.git] / src / chanserv.c
index 365d000e91d845b21fca08a6b86d9f74ab4318ce..ad857494e59b3df489796278ad4852388542c6fb 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." },
@@ -337,8 +339,8 @@ static const struct message_entry msgtab[] = {
 
 /* Access information */
     { "CSMSG_IS_CHANSERV", "$b$C$b is the $bchannel service bot$b." },
-    { "CSMSG_ACCESS_SELF_ONLY", "You may only see the list of infolines for yourself (by using $b%s$b with no arguments)." },
-    { "CSMSG_SQUAT_ACCESS", "You do not have access to any channels." },
+    { "CSMSG_MYACCESS_SELF_ONLY", "You may only see the list of infolines for yourself (by using $b%s$b with no arguments)." },
+    { "CSMSG_SQUAT_ACCESS", "$b%s$b does not have access to any channels." },
     { "CSMSG_INFOLINE_LIST", "Showing all channel entries for account $b%s$b:" },
     { "CSMSG_USER_NO_ACCESS", "%s lacks access to %s." },
     { "CSMSG_USER_HAS_ACCESS", "%s has access $b%d$b in %s." },
@@ -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))
@@ -1863,7 +1864,6 @@ static CHANSERV_FUNC(cmd_move)
     if(!(target = GetChannel(argv[1])))
     {
         target = AddChannel(argv[1], now, NULL, NULL);
-        LockChannel(target);
         if(!IsSuspended(channel->channel_info))
             AddChannelUser(chanserv, target);
     }
@@ -1881,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);
@@ -1905,6 +1905,7 @@ static CHANSERV_FUNC(cmd_move)
        DelChannelUser(chanserv, channel, reason2, 0);
     }
     UnlockChannel(channel);
+    LockChannel(target);
     global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason);
     return 1;
 }
@@ -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)
@@ -2787,7 +2788,8 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
                         free(bData->reason);
                    bData->reason = strdup(reason);
                     safestrncpy(bData->owner, (user->handle_info ? user->handle_info->handle : user->nick), sizeof(bData->owner));
-                   reply("CSMSG_REASON_CHANGE", ban);
+                    if(cmd)
+                        reply("CSMSG_REASON_CHANGE", ban);
                    if(!bData->expires)
                         goto post_add_ban;
                }
@@ -2818,7 +2820,11 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
                        if(bData->expires)
                            timeq_add(bData->expires, expire_ban, bData);
 
-                       if(duration)
+                        if(!cmd)
+                        {
+                            /* automated kickban */
+                        }
+                       else if(duration)
                            reply("CSMSG_BAN_EXTENDED", ban, intervalString(interval, duration));
                        else
                            reply("CSMSG_BAN_ADDED", name, channel->name);
@@ -2826,7 +2832,8 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
                        goto post_add_ban;
                    }
                }
-               reply("CSMSG_REDUNDANT_BAN", name, channel->name);
+                if(cmd)
+                    reply("CSMSG_REDUNDANT_BAN", name, channel->name);
 
                free(ban);
                return 0;
@@ -2875,7 +2882,8 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
 
        if(channel->banlist.used >= MAXBANS)
        {
-           reply("CSMSG_BANLIST_FULL", channel->name);
+            if(cmd)
+                reply("CSMSG_BANLIST_FULL", channel->name);
            free(ban);
            return 0;
        }
@@ -2901,7 +2909,8 @@ eject_user(struct userNode *user, struct chanNode *channel, unsigned int argc, c
 
         if(exists && (action == ACTION_BAN))
        {
-            reply("CSMSG_REDUNDANT_BAN", name, channel->name);
+            if(cmd)
+                reply("CSMSG_REDUNDANT_BAN", name, channel->name);
             free(ban);
             return 0;
         }
@@ -3133,61 +3142,57 @@ static CHANSERV_FUNC(cmd_open)
     return 1;
 }
 
-static CHANSERV_FUNC(cmd_access)
+static CHANSERV_FUNC(cmd_myaccess)
 {
-    struct userNode *target;
     struct handle_info *target_handle;
     struct userData *uData;
-    int helping;
-    char prefix[MAXLEN];
+    const char *chanName;
 
-    if(!channel)
+    if(argc < 2)
+        target_handle = user->handle_info;
+    else if(!IsHelping(user))
     {
-        struct userData *uData;
-        const char *chanName;
-        int hide = 0;
+        reply("CSMSG_MYACCESS_SELF_ONLY", argv[0]);
+        return 0;
+    }
+    else if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
+        return 0;
 
-        target_handle = user->handle_info;
-        if(!target_handle)
-        {
-            reply("MSG_AUTHENTICATE");
-            return 0;
-        }
-        if(argc > 1)
-        {
-            if(!IsHelping(user))
-            {
-                reply("CSMSG_ACCESS_SELF_ONLY", argv[0]);
-                return 0;
-            }
+    if(!target_handle->channels)
+    {
+        reply("CSMSG_SQUAT_ACCESS", target_handle->handle);
+        return 1;
+    }
 
-            if(!(target_handle = modcmd_get_handle_info(user, argv[1])))
-                return 0;
-            hide = 1;
-        }
-        if(!target_handle->channels)
-        {
-            reply("CSMSG_SQUAT_ACCESS");
-            return 1;
-        }
-        reply("CSMSG_INFOLINE_LIST", target_handle->handle);
-        for(uData = target_handle->channels; uData; uData = uData->u_next)
-        {
-            struct chanData *cData = uData->channel;
+    reply("CSMSG_INFOLINE_LIST", target_handle->handle);
+    for(uData = target_handle->channels; uData; uData = uData->u_next)
+    {
+        struct chanData *cData = uData->channel;
 
-            if(uData->access > UL_OWNER)
-                continue;
-            if(IsProtected(cData) && hide && !GetTrueChannelAccess(cData, user->handle_info))
-                continue;
-            chanName = cData->channel->name;
-            if(uData->info)
-                send_message_type(4, user, cmd->parent->bot, "[%s (%d)] %s", chanName, uData->access, uData->info);
-            else
-                send_message_type(4, user, cmd->parent->bot, "[%s (%d)]", chanName, uData->access);
-        }
-        return 1;
+        if(uData->access > UL_OWNER)
+            continue;
+        if(IsProtected(cData)
+           && (target_handle != user->handle_info)
+           && !GetTrueChannelAccess(cData, user->handle_info))
+            continue;
+        chanName = cData->channel->name;
+        if(uData->info)
+            send_message_type(4, user, cmd->parent->bot, "[%s (%d)] %s", chanName, uData->access, uData->info);
+        else
+            send_message_type(4, user, cmd->parent->bot, "[%s (%d)]", chanName, uData->access);
     }
 
+    return 1;
+}
+
+static CHANSERV_FUNC(cmd_access)
+{
+    struct userNode *target;
+    struct handle_info *target_handle;
+    struct userData *uData;
+    int helping;
+    char prefix[MAXLEN];
+
     if(argc < 2)
     {
        target = user;
@@ -3537,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;
     }
 
@@ -4314,11 +4321,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;
@@ -4337,11 +4344,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;
@@ -4373,7 +4380,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);
@@ -4880,35 +4887,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;
@@ -5638,20 +5616,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;
 }
 
@@ -5676,10 +5645,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);
 }
 
@@ -5744,7 +5712,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)
     {
@@ -5762,8 +5730,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;
@@ -5877,7 +5847,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)
     {
@@ -5909,8 +5879,11 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
                 change.args[0].mode = MODE_CHANOP;
             else if(channel->access >= cn->channel_info->lvlOpts[lvlGiveVoice])
                 change.args[0].mode = MODE_VOICE;
+            else
+                change.args[0].mode = 0;
             change.args[0].member = mn;
-            mod_chanmode_announce(chanserv, cn, &change);
+            if(change.args[0].mode)
+                mod_chanmode_announce(chanserv, cn, &change);
         }
 
        channel->seen = now;
@@ -6122,7 +6095,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)
@@ -6620,7 +6593,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);
@@ -7038,7 +7011,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);
 
@@ -7075,7 +7048,8 @@ init_chanserv(const char *nick)
     DEFINE_COMMAND(bans, 1, MODCMD_REQUIRE_REGCHAN, "access", "1", "flags", "+nolog", NULL);
     DEFINE_COMMAND(peek, 1, MODCMD_REQUIRE_REGCHAN, "access", "op", "flags", "+nolog", NULL);
 
-    DEFINE_COMMAND(access, 1, 0, "flags", "+nolog,+acceptchan", NULL);
+    DEFINE_COMMAND(myaccess, 1, MODCMD_REQUIRE_AUTHED, NULL);
+    DEFINE_COMMAND(access, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog,+joinable", NULL);
     DEFINE_COMMAND(users, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog,+joinable", NULL);
     DEFINE_COMMAND(wlist, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog,+joinable", NULL);
     DEFINE_COMMAND(clist, 1, MODCMD_REQUIRE_REGCHAN, "flags", "+nolog,+joinable", NULL);