]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/opserv.c
Checking in some .in files for compiling without autoconf/automake trouble
[irc/evilnet/x3.git] / src / opserv.c
index a63c0e148141ec2dd45c3823c7f87f386a6d4d1d..011f8cebeb42c463f515ee5502a1842fe0ecff9d 100644 (file)
@@ -101,6 +101,8 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_NO_CHANNEL_MODES", "Channel $b%s$b had no modes to clear." },
     { "OSMSG_DEOP_DONE", "Deopped the requested lusers." },
     { "OSMSG_DEOPALL_DONE", "Deopped everyone on $b%s$b." },
+    { "OSMSG_DEHOP_DONE", "Dehalfopped the requested lusers." },
+    { "OSMSG_DEHOPALL_DONE", "Dehalfopped everyone on $b%s$b." },
     { "OSMSG_NO_DEBUG_CHANNEL", "No debug channel has been configured." },
     { "OSMSG_INVITE_DONE", "Invited $b%s$b to $b%s$b." },
     { "OSMSG_ALREADY_THERE", "You are already in $b%s$b." },
@@ -112,6 +114,8 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_MODE_SET", "I have set the modes for $b%s$b." },
     { "OSMSG_OP_DONE", "Opped the requested lusers." },
     { "OSMSG_OPALL_DONE", "Opped everyone on $b%s$b." },
+    { "OSMSG_HOP_DONE", "Halfopped the requested lusers." },
+    { "OSMSG_HOPALL_DONE", "Halfopped everyone on $b%s$b." },
     { "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" },
     { "OSMSG_WHOIS_NICK", "Nick    : %s" },
     { "OSMSG_WHOIS_HOST", "Host    : %s@%s" },
@@ -177,6 +181,7 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_CLONE_JOINED", "$b%s$b has joined $b%s$b." },
     { "OSMSG_CLONE_PARTED", "$b%s$b has left $b%s$b." },
     { "OSMSG_OPS_GIVEN", "I have given ops in $b%s$b to $b%s$b." },
+    { "OSMSG_HOPS_GIVEN", "I have given halfops in $b%s$b to $b%s$b." },
     { "OSMSG_CLONE_SAID", "$b%s$b has spoken to $b%s$b." },
     { "OSMSG_UNKNOWN_SUBCOMMAND", "$b%s$b is not a valid subcommand of $b%s$b." },
     { "OSMSG_UNKNOWN_OPTION", "$b%s$b has not been set." },
@@ -244,6 +249,8 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_CHANINFO_TOPIC_UNKNOWN", "Topic: (none / not gathered)" },
     { "OSMSG_CHANINFO_BAN_COUNT", "Bans (%d):" },
     { "OSMSG_CHANINFO_BAN", "%%s by %%s (%a %b %d %H:%M:%S %Y)" },
+    { "OSMSG_CHANINFO_EXEMPT_COUNT", "Exempts (%d):" },
+    { "OSMSG_CHANINFO_EXEMPT", "%%s by %%s (%a %b %d %H:%M:%S %Y)" },
     { "OSMSG_CHANINFO_MANY_USERS", "%d users (\"/msg $S %s %s users\" for the list)" },
     { "OSMSG_CHANINFO_USER_COUNT", "Users (%d):" },
     { "OSMSG_CSEARCH_CHANNEL_INFO", "%s [%d users] %s %s" },
@@ -402,16 +409,16 @@ static MODCMD_FUNC(cmd_ban)
     change.argc = 1;
     change.args[0].mode = MODE_BAN;
     if (is_ircmask(argv[1]))
-        change.args[0].hostmask = strdup(argv[1]);
+        change.args[0].u.hostmask = strdup(argv[1]);
     else if ((victim = GetUserH(argv[1])))
-        change.args[0].hostmask = generate_hostmask(victim, 0);
+        change.args[0].u.hostmask = generate_hostmask(victim, 0);
     else {
        reply("OSMSG_INVALID_IRCMASK", argv[1]);
        return 0;
     }
     modcmd_chanmode_announce(&change);
-    reply("OSMSG_ADDED_BAN", change.args[0].hostmask, channel->name);
-    free((char*)change.args[0].hostmask);
+    reply("OSMSG_ADDED_BAN", change.args[0].u.hostmask, channel->name);
+    free((char*)change.args[0].u.hostmask);
     return 1;
 }
 
@@ -420,6 +427,7 @@ static MODCMD_FUNC(cmd_chaninfo)
     char buffer[MAXLEN];
     const char *fmt;
     struct banNode *ban;
+    struct exemptNode *exempt;
     struct modeNode *moden;
     unsigned int n;
 
@@ -449,6 +457,15 @@ static MODCMD_FUNC(cmd_chaninfo)
            send_message_type(4, user, cmd->parent->bot, buffer, ban->ban, ban->who);
        }
     }
+    if (channel->exemptlist.used) {
+        reply("OSMSG_CHANINFO_EXEMPT_COUNT", channel->exemptlist.used);
+        fmt = user_find_message(user, "OSMSG_CHANINFO_EXEMPT");
+        for (n = 0; n < channel->exemptlist.used; n++) {
+            exempt = channel->exemptlist.list[n];
+            strftime(buffer, sizeof(buffer), fmt, localtime(&exempt->set));
+            send_message_type(4, user, cmd->parent->bot, buffer, exempt->exempt, exempt->who);
+        }
+    }
     if ((argc < 2) && (channel->members.used >= 50)) {
         /* early out unless they ask for users */
         reply("OSMSG_CHANINFO_MANY_USERS", channel->members.used, argv[0], channel->name);
@@ -460,14 +477,19 @@ static MODCMD_FUNC(cmd_chaninfo)
        if (moden->modes & MODE_CHANOP)
             send_message_type(4, user, cmd->parent->bot, " @%s (%s@%s)", moden->user->nick, moden->user->ident, moden->user->hostname);
     }
+    for (n=0; n<channel->members.used; n++) {
+        moden = channel->members.list[n];
+        if ((moden->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) == MODE_HALFOP)
+            send_message_type(4, user, cmd->parent->bot, " %s%s (%s@%s)", "%", moden->user->nick, moden->user->ident, moden->user->hostname);
+    }
     for (n=0; n<channel->members.used; n++) {
        moden = channel->members.list[n];
-       if ((moden->modes & (MODE_CHANOP|MODE_VOICE)) == MODE_VOICE)
+       if ((moden->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) == MODE_VOICE)
             send_message_type(4, user, cmd->parent->bot, " +%s (%s@%s)", moden->user->nick, moden->user->ident, moden->user->hostname);
     }
     for (n=0; n<channel->members.used; n++) {
        moden = channel->members.list[n];
-       if ((moden->modes & (MODE_CHANOP|MODE_VOICE)) == 0)
+       if ((moden->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) == 0)
             send_message_type(4, user, cmd->parent->bot, "  %s (%s@%s)", moden->user->nick, moden->user->ident, moden->user->hostname);
     }
     return 1;
@@ -522,7 +544,7 @@ static MODCMD_FUNC(cmd_clearbans)
     change = mod_chanmode_alloc(channel->banlist.used);
     for (ii=0; ii<channel->banlist.used; ii++) {
         change->args[ii].mode = MODE_REMOVE | MODE_BAN;
-        change->args[ii].hostmask = channel->banlist.list[ii]->ban;
+        change->args[ii].u.hostmask = channel->banlist.list[ii]->ban;
     }
     modcmd_chanmode_announce(change);
     mod_chanmode_free(change);
@@ -559,7 +581,7 @@ static MODCMD_FUNC(cmd_deop)
             || !(mn->modes & MODE_CHANOP))
             continue;
         change->args[count].mode = MODE_REMOVE | MODE_CHANOP;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -570,6 +592,31 @@ static MODCMD_FUNC(cmd_deop)
     return 1;
 }
 
+static MODCMD_FUNC(cmd_dehop)
+{
+    struct mod_chanmode *change;
+    unsigned int arg, count;
+
+    change = mod_chanmode_alloc(argc-1);
+    for (arg = 1, count = 0; arg < argc; ++arg) {
+        struct userNode *victim = GetUserH(argv[arg]);
+        struct modeNode *mn;
+        if (!victim || IsService(victim)
+            || !(mn = GetUserMode(channel, victim))
+            || !(mn->modes & MODE_HALFOP))
+            continue;
+        change->args[count].mode = MODE_REMOVE | MODE_HALFOP;
+        change->args[count++].u.member = mn;
+    }
+    if (count) {
+        change->argc = count;
+        modcmd_chanmode_announce(change);
+    }
+    mod_chanmode_free(change);
+    reply("OSMSG_DEHOP_DONE");
+    return 1;
+}
+
 static MODCMD_FUNC(cmd_deopall)
 {
     struct mod_chanmode *change;
@@ -581,7 +628,7 @@ static MODCMD_FUNC(cmd_deopall)
        if (IsService(mn->user) || !(mn->modes & MODE_CHANOP))
             continue;
         change->args[count].mode = MODE_REMOVE | MODE_CHANOP;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -592,6 +639,28 @@ static MODCMD_FUNC(cmd_deopall)
     return 1;
 }
 
+static MODCMD_FUNC(cmd_dehopall)
+{
+    struct mod_chanmode *change;
+    unsigned int ii, count;
+
+    change = mod_chanmode_alloc(channel->members.used);
+    for (ii = count = 0; ii < channel->members.used; ++ii) {
+        struct modeNode *mn = channel->members.list[ii];
+        if (IsService(mn->user) || !(mn->modes & MODE_HALFOP))
+            continue;
+        change->args[count].mode = MODE_REMOVE | MODE_HALFOP;
+        change->args[count++].u.member = mn;
+    }
+    if (count) {
+        change->argc = count;
+        modcmd_chanmode_announce(change);
+    }
+    mod_chanmode_free(change);
+    reply("OSMSG_DEHOPALL_DONE", channel->name);
+    return 1;
+}
+
 static MODCMD_FUNC(cmd_rehash)
 {
     extern char *services_config;
@@ -856,6 +925,8 @@ opserv_ison(struct userNode *tell, struct userNode *target, const char *message)
        }
        if (mn->modes & MODE_CHANOP)
             buff[count++] = '@';
+        if (mn->modes & MODE_HALFOP)
+            buff[count++] = '%';
        if (mn->modes & MODE_VOICE)
             buff[count++] = '+';
        memcpy(buff+count, mn->channel->name, here_len);
@@ -886,7 +957,7 @@ static MODCMD_FUNC(cmd_inviteme)
        return 0;
     }
     if (GetUserMode(opserv_conf.debug_channel, user)) {
-        reply("OSMSG_ALREADY_THERE", channel->name);
+        reply("OSMSG_ALREADY_THERE", opserv_conf.debug_channel->name);
         return 0;
     }
     irc_invite(cmd->parent->bot, target, opserv_conf.debug_channel);
@@ -913,7 +984,7 @@ static MODCMD_FUNC(cmd_join)
         reply("MSG_NOT_CHANNEL_NAME");
         return 0;
     } else if (!(channel = GetChannel(argv[1]))) {
-        channel = AddChannel(argv[1], now, NULL, NULL);
+        channel = AddChannel(argv[1], now, NULL, NULL, NULL);
         AddChannelUser(bot, channel)->modes |= MODE_CHANOP;
     } else if (GetUserMode(channel, bot)) {
         reply("OSMSG_ALREADY_JOINED", channel->name);
@@ -923,7 +994,7 @@ static MODCMD_FUNC(cmd_join)
         mod_chanmode_init(&change);
         change.argc = 1;
         change.args[0].mode = MODE_CHANOP;
-        change.args[0].member = AddChannelUser(bot, channel);
+        change.args[0].u.member = AddChannelUser(bot, channel);
         modcmd_chanmode_announce(&change);
     }
     irc_fetchtopic(bot, channel->name);
@@ -968,7 +1039,7 @@ static MODCMD_FUNC(cmd_kickall)
         struct mod_chanmode change;
         mod_chanmode_init(&change);
         change.args[0].mode = MODE_CHANOP;
-        change.args[0].member = AddChannelUser(bot, channel);
+        change.args[0].u.member = AddChannelUser(bot, channel);
         modcmd_chanmode_announce(&change);
     }
     if (argc < 2) {
@@ -1018,7 +1089,7 @@ static MODCMD_FUNC(cmd_kickban)
     mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].mode = MODE_BAN;
-    change.args[0].hostmask = mask = generate_hostmask(target, 0);
+    change.args[0].u.hostmask = mask = generate_hostmask(target, 0);
     modcmd_chanmode_announce(&change);
     KickChannelUser(target, channel, cmd->parent->bot, reason);
     free(mask);
@@ -1038,15 +1109,16 @@ static MODCMD_FUNC(cmd_kickbanall)
     if (!(inchan = GetUserMode(channel, bot) ? 1 : 0)) {
         change = mod_chanmode_alloc(2);
         change->args[0].mode = MODE_CHANOP;
-        change->args[0].member = AddChannelUser(bot, channel);
+        change->args[0].u.member = AddChannelUser(bot, channel);
         change->args[1].mode = MODE_BAN;
-        change->args[1].hostmask = "*!*@*";
+        change->args[1].u.hostmask = "*!*@*";
     } else {
         change = mod_chanmode_alloc(1);
         change->args[0].mode = MODE_BAN;
-        change->args[0].hostmask = "*!*@*";
+        change->args[0].u.hostmask = "*!*@*";
     }
     modcmd_chanmode_announce(change);
+    mod_chanmode_free(change);
     if (argc < 2) {
        reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1);
        sprintf(reason, OSMSG_KICK_REQUESTED, user->nick);
@@ -1116,7 +1188,7 @@ static MODCMD_FUNC(cmd_op)
         if (mn->modes & MODE_CHANOP)
             continue;
         change->args[count].mode = MODE_CHANOP;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -1127,6 +1199,33 @@ static MODCMD_FUNC(cmd_op)
     return 1;
 }
 
+static MODCMD_FUNC(cmd_hop)
+{
+    struct mod_chanmode *change;
+    unsigned int arg, count;
+
+    change = mod_chanmode_alloc(argc-1);
+    for (arg = 1, count = 0; arg < argc; ++arg) {
+        struct userNode *victim;
+        struct modeNode *mn;
+        if (!(victim = GetUserH(argv[arg])))
+            continue;
+        if (!(mn =  GetUserMode(channel, victim)))
+            continue;
+        if (mn->modes & MODE_HALFOP)
+            continue;
+        change->args[count].mode = MODE_HALFOP;
+        change->args[count++].u.member = mn;
+    }
+    if (count) {
+        change->argc = count;
+        modcmd_chanmode_announce(change);
+    }
+    mod_chanmode_free(change);
+    reply("OSMSG_HOP_DONE");
+    return 1;
+}
+
 static MODCMD_FUNC(cmd_opall)
 {
     struct mod_chanmode *change;
@@ -1138,7 +1237,7 @@ static MODCMD_FUNC(cmd_opall)
        if (mn->modes & MODE_CHANOP)
             continue;
         change->args[count].mode = MODE_CHANOP;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -1149,6 +1248,28 @@ static MODCMD_FUNC(cmd_opall)
     return 1;
 }
 
+static MODCMD_FUNC(cmd_hopall)
+{
+    struct mod_chanmode *change;
+    unsigned int ii, count;
+
+    change = mod_chanmode_alloc(channel->members.used);
+    for (ii = count = 0; ii < channel->members.used; ++ii) {
+        struct modeNode *mn = channel->members.list[ii];
+        if (mn->modes & MODE_HALFOP)
+            continue;
+        change->args[count].mode = MODE_HALFOP;
+        change->args[count++].u.member = mn;
+    }
+    if (count) {
+        change->argc = count;
+        modcmd_chanmode_announce(change);
+    }
+    mod_chanmode_free(change);
+    reply("OSMSG_HOPALL_DONE", channel->name);
+    return 1;
+}
+
 static MODCMD_FUNC(cmd_whois)
 {
     struct userNode *target;
@@ -1159,10 +1280,8 @@ static MODCMD_FUNC(cmd_whois)
     if (argv[1][0] == '*')
         target = GetUserN(argv[1]+1);
     else
-        target = GetUserH(argv[1]);
-#else
-    target = GetUserH(argv[1]);
 #endif
+    target = GetUserH(argv[1]);
     if (!target) {
         reply("MSG_NICK_UNKNOWN", argv[1]);
         return 0;
@@ -1180,7 +1299,11 @@ static MODCMD_FUNC(cmd_whois)
        if (IsOper(target)) buffer[bpos++] = 'o';
        if (IsGlobal(target)) buffer[bpos++] = 'g';
        if (IsServNotice(target)) buffer[bpos++] = 's';
-       if (IsHelperIrcu(target)) buffer[bpos++] = 'h';
+
+       // sethost - reed/apples
+       // if (IsHelperIrcu(target)) buffer[bpos++] = 'h';
+       if (IsSetHost(target)) buffer[bpos++] = 'h';
+
        if (IsService(target)) buffer[bpos++] = 'k';
        if (IsDeaf(target)) buffer[bpos++] = 'd';
         if (IsHiddenHost(target)) buffer[bpos++] = 'x';
@@ -1211,7 +1334,7 @@ static MODCMD_FUNC(cmd_unban)
     mod_chanmode_init(&change);
     change.argc = 1;
     change.args[0].mode = MODE_REMOVE | MODE_BAN;
-    change.args[0].hostmask = argv[1];
+    change.args[0].u.hostmask = argv[1];
     modcmd_chanmode_announce(&change);
     reply("OSMSG_UNBAN_DONE", channel->name);
     return 1;
@@ -1225,10 +1348,10 @@ static MODCMD_FUNC(cmd_voiceall)
     change = mod_chanmode_alloc(channel->members.used);
     for (ii = count = 0; ii < channel->members.used; ++ii) {
        struct modeNode *mn = channel->members.list[ii];
-       if (mn->modes & (MODE_CHANOP|MODE_VOICE))
+       if (mn->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE))
             continue;
         change->args[count].mode = MODE_VOICE;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -1250,7 +1373,7 @@ static MODCMD_FUNC(cmd_devoiceall)
        if (!(mn->modes & MODE_VOICE))
             continue;
         change->args[count].mode = MODE_REMOVE | MODE_VOICE;
-        change->args[count++].member = mn;
+        change->args[count++].u.member = mn;
     }
     if (count) {
         change->argc = count;
@@ -1802,9 +1925,9 @@ opserv_shutdown_channel(struct chanNode *channel, const char *reason)
     change = mod_chanmode_alloc(2);
     change->modes_set = MODE_SECRET | MODE_INVITEONLY;
     change->args[0].mode = MODE_CHANOP;
-    change->args[0].member = AddChannelUser(opserv, channel);
+    change->args[0].u.member = AddChannelUser(opserv, channel);
     change->args[1].mode = MODE_BAN;
-    change->args[1].hostmask = "*!*@*";
+    change->args[1].u.hostmask = "*!*@*";
     mod_chanmode_announce(opserv, channel, change);
     mod_chanmode_free(change);
     for (nn=channel->members.used; nn>0; ) {
@@ -1883,7 +2006,7 @@ opserv_join_check(struct modeNode *mNode)
             if (!GetUserMode(channel, opserv)) {
                 /* If we aren't in the channel, join it. */
                 change.args[0].mode = MODE_CHANOP;
-                change.args[0].member = AddChannelUser(opserv, channel);
+                change.args[0].u.member = AddChannelUser(opserv, channel);
                 change.argc++;
             }
             if (!(channel->modes & MODE_MODERATED))
@@ -2255,7 +2378,7 @@ static MODCMD_FUNC(cmd_clone)
     channel = GetChannel(argv[3]);
     if (!irccasecmp(argv[1], "JOIN")) {
        if (!channel
-           && !(channel = AddChannel(argv[3], now, NULL, NULL))) {
+           && !(channel = AddChannel(argv[3], now, NULL, NULL, NULL))) {
            reply("MSG_CHANNEL_UNKNOWN", argv[3]);
            return 0;
        }
@@ -2285,8 +2408,8 @@ static MODCMD_FUNC(cmd_clone)
         mod_chanmode_init(&change);
         change.argc = 1;
         change.args[0].mode = MODE_CHANOP;
-        change.args[0].member = GetUserMode(channel, clone);
-        if (!change.args[0].member) {
+        change.args[0].u.member = GetUserMode(channel, clone);
+        if (!change.args[0].u.member) {
             reply("OSMSG_NOT_ON_CHANNEL", clone->nick, channel->name);
             return 0;
        }
@@ -2294,6 +2417,24 @@ static MODCMD_FUNC(cmd_clone)
        reply("OSMSG_OPS_GIVEN", channel->name, clone->nick);
        return 1;
     }
+    if (!irccasecmp(argv[1], "HOP")) {
+        struct mod_chanmode change;
+        if (!channel) {
+            reply("MSG_CHANNEL_UNKNOWN", argv[3]);
+            return 0;
+        }
+        mod_chanmode_init(&change);
+        change.argc = 1;
+        change.args[0].mode = MODE_HALFOP;
+        change.args[0].u.member = GetUserMode(channel, clone);
+        if (!change.args[0].u.member) {
+            reply("OSMSG_NOT_ON_CHANNEL", clone->nick, channel->name);
+            return 0;
+        }
+        modcmd_chanmode_announce(&change);
+        reply("OSMSG_HOPS_GIVEN", channel->name, clone->nick);
+        return 1;
+    }
     if (argc < 5) {
        reply("MSG_MISSING_PARAMS", argv[1]);
        OPSERV_SYNTAX();
@@ -2954,11 +3095,17 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in
                 case '#':
                     goto find_channel;
                 case '-':
-                    discrim->chan_no_modes  |= MODE_CHANOP | MODE_VOICE;
+                    discrim->chan_no_modes  |= MODE_CHANOP | MODE_HALFOP | MODE_VOICE;
                     break;
                 case '+':
                     discrim->chan_req_modes |= MODE_VOICE;
                     discrim->chan_no_modes  |= MODE_CHANOP;
+                    discrim->chan_no_modes  |= MODE_HALFOP;
+                    break;
+                case '%':
+                    discrim->chan_req_modes |= MODE_HALFOP;
+                    discrim->chan_no_modes  |= MODE_CHANOP;
+                    discrim->chan_no_modes  |= MODE_VOICE;
                     break;
                 case '@':
                     discrim->chan_req_modes |= MODE_CHANOP;
@@ -2977,7 +3124,7 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in
                     send_message(user, opserv, "MSG_CHANNEL_UNKNOWN", argv[i]);
                     goto fail;
                 } else {
-                    discrim->channel = AddChannel(argv[i]+j, now, NULL, NULL);
+                    discrim->channel = AddChannel(argv[i]+j, now, NULL, NULL, NULL);
                 }
            }
             LockChannel(discrim->channel);
@@ -3903,7 +4050,7 @@ opserv_conf_read(void)
         str2 = database_get_data(conf_node, KEY_DEBUG_CHANNEL_MODES, RECDB_QSTRING);
         if (!str2)
             str2 = "+tinms";
-       opserv_conf.debug_channel = AddChannel(str, now, str2, NULL);
+       opserv_conf.debug_channel = AddChannel(str, now, str2, NULL, NULL);
         AddChannelUser(opserv, opserv_conf.debug_channel)->modes |= MODE_CHANOP;
     } else {
        opserv_conf.debug_channel = NULL;
@@ -3913,7 +4060,7 @@ opserv_conf_read(void)
         str2 = database_get_data(conf_node, KEY_ALERT_CHANNEL_MODES, RECDB_QSTRING);
         if (!str2)
             str2 = "+tns";
-       opserv_conf.alert_channel = AddChannel(str, now, str2, NULL);
+       opserv_conf.alert_channel = AddChannel(str, now, str2, NULL, NULL);
         AddChannelUser(opserv, opserv_conf.alert_channel)->modes |= MODE_CHANOP;
     } else {
        opserv_conf.alert_channel = NULL;
@@ -3923,7 +4070,7 @@ opserv_conf_read(void)
         str2 = database_get_data(conf_node, KEY_STAFF_AUTH_CHANNEL_MODES, RECDB_QSTRING);
         if (!str2)
             str2 = "+timns";
-        opserv_conf.staff_auth_channel = AddChannel(str, now, str2, NULL);
+        opserv_conf.staff_auth_channel = AddChannel(str, now, str2, NULL, NULL);
         AddChannelUser(opserv, opserv_conf.staff_auth_channel)->modes |= MODE_CHANOP;
     } else {
         opserv_conf.staff_auth_channel = NULL;
@@ -4022,8 +4169,10 @@ void
 init_opserv(const char *nick)
 {
     OS_LOG = log_register_type("OpServ", "file:opserv.log");
-    if (nick)
-        opserv = AddService(nick, "Oper Services", NULL);
+    if (nick) {
+        const char *modes = conf_get_data("services/opserv/modes", RECDB_QSTRING);
+        opserv = AddService(nick, modes ? modes : NULL, "Oper Services", NULL);
+    }
     conf_register_reload(opserv_conf_read);
 
     memset(level_strings, 0, sizeof(level_strings));
@@ -4052,6 +4201,8 @@ init_opserv(const char *nick)
     opserv_define_func("DELTRUST", cmd_deltrust, 800, 0, 2);
     opserv_define_func("DEOP", cmd_deop, 100, 2, 2);
     opserv_define_func("DEOPALL", cmd_deopall, 400, 2, 0);
+    opserv_define_func("DEHOP", cmd_dehop, 100, 2, 2);
+    opserv_define_func("DEHOPALL", cmd_dehopall, 400, 2, 0);
     opserv_define_func("DEVOICEALL", cmd_devoiceall, 300, 2, 0);
     opserv_define_func("DIE", cmd_die, 900, 0, 2);
     opserv_define_func("DUMP", cmd_dump, 999, 0, 2);
@@ -4075,6 +4226,8 @@ init_opserv(const char *nick)
     opserv_define_func("MODE", cmd_mode, 100, 2, 2);
     opserv_define_func("OP", cmd_op, 100, 2, 2);
     opserv_define_func("OPALL", cmd_opall, 400, 2, 0);
+    opserv_define_func("HOP", cmd_hop, 100, 2, 2);
+    opserv_define_func("HOPALL", cmd_hopall, 400, 2, 0);
     opserv_define_func("PART", cmd_part, 601, 0, 2);
     opserv_define_func("QUERY", cmd_query, 0, 0, 0);
     opserv_define_func("RAW", cmd_raw, 999, 0, 2);