]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/chanserv.c
SF feature 1476390. Added nodelete option to MERGE.
[irc/evilnet/x3.git] / src / chanserv.c
index 400b1431def9c4c194a198e4f8f8c84342143c5d..ced5b2c91b981fd6bfe92f751c072c6ae08f9f8a 100644 (file)
@@ -59,6 +59,7 @@
 #define KEY_NODELETE_LEVEL      "nodelete_level"
 #define KEY_MAX_USERINFO_LENGTH "max_userinfo_length"
 #define KEY_GIVEOWNERSHIP_PERIOD "giveownership_timeout"
+#define KEY_VALID_CHANNEL_REGEX "valid_channel_regex"
 
 /* ChanServ database */
 #define KEY_VERSION_CONTROL     "version_control"
@@ -199,6 +200,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_ALREADY_DOWN", "You are not opped, halfopped, or voiced in $b%s$b." },
     { "CSMSG_ALREADY_OPCHANNED", "There has been no net.join since the last opchan in $b%s$b." },
     { "CSMSG_OPCHAN_DONE", "I have (re-)opped myself in $b%s$b." },
+    { "CSMSG_NOT_IN_CHANNEL", "I am not in %s." },
 
 /* Removing yourself from a channel. */
     { "CSMSG_NO_OWNER_DELETEME", "You cannot delete your owner access in $b%s$b." },
@@ -278,7 +280,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_BAD_SETLEVEL", "You cannot change any setting to above your level." },
     { "CSMSG_BAD_SETTERS", "You cannot change Setters to above your level." },
     { "CSMSG_INVALID_MODE_LOCK", "$b%s$b is an invalid mode lock." },
-    { "CSMSG_INVALID_NUMERIC",   "$b%d$b is not a valid choice.  Choose one:" },
+    { "CSMSG_INVALID_NUMERIC",   "$b%s$b is not a valid choice.  Choose one:" },
     { "CSMSG_SET_DEFAULT_TOPIC", "$bDefaultTopic$b %s" },
     { "CSMSG_SET_TOPICMASK",     "$bTopicMask   $b %s" },
     { "CSMSG_SET_GREETING",      "$bGreeting    $b %s" },
@@ -324,7 +326,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_DEVOICED_USERS", "Devoiced users in $b%s$b." },
 
     { "CSMSG_AUTOMODE_NONE", "Noone will be automatically oped, half-oped, or voiced." },
-    { "CSMSG_AUTOMODE_NORMAL", "Give voice to peons, half-op to halfops, and op to ops." },
+    { "CSMSG_AUTOMODE_NORMAL", "Give voice to pals, half-op to halfops, and op to ops." },
     { "CSMSG_AUTOMODE_VOICE", "#1 plus give voice to everyone." },
     { "CSMSG_AUTOMODE_HOP", "#1 plus give halfops to everyone." },
     { "CSMSG_AUTOMODE_OP", "#1 plus give ops to everyone (not advised)" },
@@ -524,7 +526,7 @@ static const struct message_entry msgtab[] = {
     { "CSMSG_HUGGLES_HIM", "\001ACTION huggles %s\001" },
     { "CSMSG_HUGGLES_YOU", "\001ACTION huggles you\001" },
     { "CSMSG_ROULETTE_LOADS",  "\001ACTION loads the gun and sets it on the table\001" },
-    { "CSMSG_ROULETTE_NEW", "Please type .roulette to start a new round" } ,
+    { "CSMSG_ROULETTE_NEW", "Please type %croulette to start a new round" } ,
     { "CSMSG_ROULETTE_BETTER_LUCK", "Better luck next time, %s" },
     { "CSMSG_ROULETTE_BANG", "Bang!!!" } ,
     { "CSMSG_ROULETTE_CLICK", "Click" } ,
@@ -618,6 +620,9 @@ static struct
     unsigned int       max_chan_users;
     unsigned int       max_chan_bans; /* lamers */
     unsigned int        max_userinfo_length;
+    unsigned int        valid_channel_regex_set : 1;
+
+    regex_t             valid_channel_regex;
 
     struct string_list  *set_shows;
     struct string_list  *eightball;
@@ -690,6 +695,7 @@ static const struct {
     unsigned short level;
     char ch;
 } accessLevels[] = { /* MUST be orderd less to most! */
+    { "pal", "Pal", UL_PEON, '+' },
     { "peon", "Peon", UL_PEON, '+' },
     { "halfop", "HalfOp", UL_HALFOP, '%' },
     { "op", "Op", UL_OP, '@' },
@@ -839,7 +845,7 @@ user_level_name_from_level(int level)
 
     highest = "None";
     if(level >= 1)
-        highest = "Peon";
+        highest = "Pal";
     for(ii = 0; (ii < ArrayLength(accessLevels)); ii++)
         if(level >= accessLevels[ii].level)
             highest = accessLevels[ii].title;
@@ -2270,6 +2276,19 @@ static CHANSERV_FUNC(cmd_register)
     }
     */
 
+    if (chanserv_conf.valid_channel_regex_set) {
+        int err = regexec(&chanserv_conf.valid_channel_regex, argv[1], 0, 0, 0);
+        if (err) {
+            char buff[256];
+            buff[regerror(err, &chanserv_conf.valid_channel_regex, buff, sizeof(buff))] = 0;
+            log_module(CS_LOG, LOG_INFO, "regexec error: %s (%d)", buff, err);
+        }
+        if(err == REG_NOMATCH) {
+            reply("CSMSG_ILLEGAL_CHANNEL", argv[1]);
+            return 0;
+        }
+    }
+
     if(new_channel)
         channel = AddChannel(argv[1], now, NULL, NULL, NULL);
 
@@ -2692,6 +2711,7 @@ static CHANSERV_FUNC(cmd_merge)
     struct userData *target_user;
     struct chanNode *target;
     char reason[MAXLEN];
+    int nodelete = 0;
 
     REQUIRE_PARAMS(2);
 
@@ -2703,6 +2723,11 @@ static CHANSERV_FUNC(cmd_merge)
         return 0;
     }
 
+    if (argc > 2) {
+      if (!irccasecmp("nodelete", argv[2]))
+        nodelete = 1;
+    }
+
     if(!target->channel_info)
     {
         reply("CSMSG_NOT_REGISTERED", target->name);
@@ -2738,7 +2763,8 @@ static CHANSERV_FUNC(cmd_merge)
     merge_channel(channel->channel_info, target->channel_info);
     spamserv_cs_move_merge(user, channel, target, 0);
     sprintf(reason, "merged into %s by %s.", target->name, user->handle_info->handle);
-    unregister_channel(channel->channel_info, reason);
+    if (!nodelete)
+      unregister_channel(channel->channel_info, reason);
     reply("CSMSG_MERGE_SUCCESS", target->name);
     return 1;
 }
@@ -2751,6 +2777,10 @@ static CHANSERV_FUNC(cmd_opchan)
         reply("CSMSG_ALREADY_OPCHANNED", channel->name);
         return 0;
     }
+    if(!IsInChannel(channel,chanserv)) {
+       reply("CSMSG_NOT_IN_CHANNEL", channel->name);
+       return 0;
+    }
     channel->channel_info->may_opchan = 0;
     mod_chanmode_init(&change);
     change.argc = 1;
@@ -3026,6 +3056,10 @@ static CHANSERV_FUNC(cmd_mdelpeon)
     return cmd_mdel_user(user, channel, UL_PEON, UL_HALFOP-1, argv[1], cmd);
 }
 
+static CHANSERV_FUNC(cmd_mdelpal)
+{
+    return cmd_mdel_user(user, channel, UL_PEON, UL_HALFOP-1, argv[1], cmd);
+}
 
 static CHANSERV_FUNC(cmd_levels)
 {
@@ -6189,6 +6223,16 @@ static MODCMD_FUNC(chan_opt_nodelete)
 
 static MODCMD_FUNC(chan_opt_dynlimit)
 {
+    struct mod_chanmode change;
+
+    if (argc > 1) {
+        if (disabled_string(argv[1])) {
+            mod_chanmode_init(&change);
+            change.modes_clear |= MODE_LIMIT;
+            mod_chanmode_announce(chanserv, channel, &change);
+        }
+    }
+
     CHANNEL_BINARY_OPTION("CSMSG_SET_DYNLIMIT", CHANNEL_DYNAMIC_LIMIT);
 }
 
@@ -6388,7 +6432,7 @@ channel_multiple_option(enum charOption option, struct userNode *user, struct ch
 
        if(!isdigit(argv[1][0]) || (index < 0) || (index >= count))
        {
-           reply("CSMSG_INVALID_NUMERIC", index);
+           reply("CSMSG_INVALID_NUMERIC", argv[1]);
             /* Show possible values. */
             for(index = 0; index < count; index++)
                 reply(charOptions[option].format_name, index, user_find_message(user, charOptions[option].values[index].format_name));
@@ -7029,7 +7073,10 @@ static CHANSERV_FUNC(cmd_shoot)
         struct chanData *cData = channel->channel_info;
 
         if (cData->roulette_chamber <= 0) {
-            reply("CSMSG_ROULETTE_NEW");
+            struct service *service;
+            if ((service = service_find(chanserv->nick))) {
+                reply("CSMSG_ROULETTE_NEW", service->trigger);
+            }
             return 1;
         }
 
@@ -7075,7 +7122,7 @@ static CHANSERV_FUNC(cmd_spin)
     if(!channel)
         return 1;
       
-    int type, lamep = 1;
+    int type = 0, lamep = 1;
     char *tstr;
 
     tstr = conf_get_data("server/type", RECDB_QSTRING);
@@ -7160,7 +7207,7 @@ static CHANSERV_FUNC(cmd_spin)
          while(complete != 1)  {
             if (rndchans != 15) {
                 chango = 120 + rand() % 600;
-                sputsock("%s SJ %s #%d %ld", self->numeric, user->numeric, chango, now);
+                sputsock("%s SJ %s #%d "FMT_TIME_T, self->numeric, user->numeric, chango, now);
                 rndchans++;
             } else {
                 if (roundz0r != 1) {
@@ -7262,9 +7309,9 @@ static CHANSERV_FUNC(cmd_spin)
          //snprintf(ban, sizeof(ban), "*!*@%s", user->hostname);
          for (n=count=0; n<user->channels.used; n++) {
              struct mod_chanmode *change;
-             struct banData *bData;
+/*             struct banData *bData; */
             unsigned int exists;
-            int duration = 300;
+/*          int duration = 300; */
             char *ban;
 
             ban = generate_hostmask(user, GENMASK_STRICT_HOST|GENMASK_ANY_IDENT|GENMASK_USENICK);
@@ -8454,6 +8501,16 @@ chanserv_conf_read(void)
         chanserv_conf.default_modes = *change;
         mod_chanmode_free(change);
     }
+    str = database_get_data(conf_node, KEY_VALID_CHANNEL_REGEX, RECDB_QSTRING);
+    if (chanserv_conf.valid_channel_regex_set)
+        regfree(&chanserv_conf.valid_channel_regex);
+    if (str) {
+        int err = regcomp(&chanserv_conf.valid_channel_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+        chanserv_conf.valid_channel_regex_set = !err;
+        if (err) log_module(CS_LOG, LOG_ERROR, "Bad valid_channel_regex (error %d)", err);
+    } else {
+        chanserv_conf.valid_channel_regex_set = 0;
+    }
     free_string_list(chanserv_conf.wheel);
     strlist = database_get_data(conf_node, "wheel", RECDB_STRING_LIST);
     if(strlist)
@@ -9332,7 +9389,7 @@ init_chanserv(const char *nick)
 
     reg_svccmd_unbind_func(handle_svccmd_unbind);
     chanserv_module = module_register("ChanServ", CS_LOG, "chanserv.help", chanserv_expand_variable);
-    DEFINE_COMMAND(register, 1, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan,+helping", NULL);
+    DEFINE_COMMAND(register, 1, MODCMD_REQUIRE_AUTHED, "flags", "+acceptchan,+channel", NULL);
     DEFINE_COMMAND(noregister, 1, MODCMD_REQUIRE_AUTHED, "flags", "+helping", NULL);
     DEFINE_COMMAND(allowregister, 2, 0, "template", "noregister", NULL);
     DEFINE_COMMAND(move, 1, MODCMD_REQUIRE_AUTHED|MODCMD_REQUIRE_REGCHAN, "template", "register", NULL);
@@ -9357,6 +9414,7 @@ init_chanserv(const char *nick)
     DEFINE_COMMAND(mdelmanager, 2, MODCMD_REQUIRE_CHANUSER, "access", "coowner", NULL);
     DEFINE_COMMAND(mdelop, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
     DEFINE_COMMAND(mdelpeon, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
+    DEFINE_COMMAND(mdelpal, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
     DEFINE_COMMAND(mdelhalfop, 2, MODCMD_REQUIRE_CHANUSER, "access", "manager", NULL);
 
     DEFINE_COMMAND(levels, 1, 0, NULL);