]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/opserv.c
Added tempshun support to OpServ trace and addalert
[irc/evilnet/x3.git] / src / opserv.c
index 571879300ea1777133859174f0a7df48392e8336..44808812f0f8e9c1c145f1d0f06f8b896199f006 100644 (file)
@@ -182,12 +182,14 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_KICKALL_DONE", "I have cleared out %s." },
     { "OSMSG_LEAVING", "Leaving $b%s$b." },
     { "OSMSG_MARK_INVALID", "Sorry, marks must contain only letters, numbers, and dashes ('-')." },
+    { "OSMSG_MARK_NOTMARKED", "Action not mark but mark supplied. (Did you mean marked?)" },
     { "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." },
     { "OMSG_BAD_SVSNICK", "$b%s$b is an invalid nickname." },
+    { "OSMSG_BAD_SVSCMDTARGET", "$b%s$b is an invalid target for %s." },
 
     { "OSMSG_WHOIS_IDENT",      "%s (%s@%s) from %d.%d.%d.%d" },
     { "OSMSG_WHOIS_NICK",       "Nick         : %s" },
@@ -217,7 +219,8 @@ static const struct message_entry msgtab[] = {
     { "OSMSG_WHOIS_HIDECHANS",  "Channel list omitted for your sanity." },
     { "OSMSG_WHOIS_VERSION",    "Version      : %s" },  
     { "OSMSG_WHOIS_SSLFP",      "SSL f/print  : %s" },
-    { "OSMSG_WHOIS_MARK",       "Mark         : %s" },  
+    { "OSMSG_WHOIS_MARK",       "Mark         : %s" },
+    { "OSMSG_WHOIS_MARKS",      "Marks        : %s" },
     { "OSMSG_WHOIS_NO_NOTICE",  "No_notices   : %s" },
     { "OSMSG_UNBAN_DONE", "Ban(s) removed from channel %s." },
     { "OSMSG_CHANNEL_VOICED", "All users on %s voiced." },
@@ -571,7 +574,7 @@ struct discrim_and_source {
     unsigned int disp_limit;
 };
 
-static discrim_t opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel);
+static discrim_t opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel, const char *action);
 static unsigned int opserv_discrim_search(discrim_t discrim, discrim_search_func dsf, void *data);
 static int gag_helper_func(struct userNode *match, void *extra);
 static int ungag_helper_func(struct userNode *match, void *extra);
@@ -583,10 +586,13 @@ typedef enum {
     REACT_GLINE,
     REACT_TRACK,
     REACT_SHUN,
+    REACT_TEMPSHUN,
     REACT_SVSJOIN,
     REACT_SVSPART,
     REACT_VERSION,
-    REACT_MARK
+    REACT_MARK,
+    REACT_NOTICEUSER,
+    REACT_MSGUSER
 } opserv_alert_reaction;
 
 struct opserv_user_alert {
@@ -1458,6 +1464,22 @@ opserv_svsjoin(struct userNode *target, UNUSED_ARG(char *src_handle), UNUSED_ARG
             return; /* channel is invite only */
         }
 
+        if (!IsOper(target) && (channel->modes & MODE_OPERSONLY)) {
+            return; /* user is not oper and channel is opers only */
+        }
+
+        if (!IsAdmin(target) && (channel->modes & MODE_ADMINSONLY)) {
+            return; /* user is not admin and channel is admin only */
+        }
+
+        if (target->handle_info && (channel->modes & MODE_REGONLY)) {
+            return; /* user is not authed and channel is authed only users */
+        }
+
+        if (!IsSSL(target) && (channel->modes & MODE_SSLONLY)) {
+            return; /* user is not SSL and channel is SSL only */
+        }
+
         if (channel->limit > 0) {
             if (channel->members.used >= channel->limit) {
                 return; /* channel is invite on */
@@ -1510,6 +1532,12 @@ opserv_shun(struct userNode *target, char *src_handle, char *reason, unsigned lo
     return shun_add(src_handle, mask, duration, reason, now, 1);
 }
 
+static void
+opserv_tempshun(struct userNode *target, char *src_handle, char *reason)
+{
+    irc_tempshun(opserv, target, 0, reason);
+}
+
 static MODCMD_FUNC(cmd_sblock)
 {
     struct userNode *target;
@@ -1566,7 +1594,7 @@ static MODCMD_FUNC(cmd_shun)
     struct shun *shun;
 
     reason = unsplit_string(argv+3, argc-3, NULL);
-    if (!is_shun(argv[1]) && !IsChannelName(argv[1]) && (argv[1][0] != '&')) {
+    if (!is_shun(argv[1])) {
         reply("MSG_INVALID_SHUN", argv[1]);
         return 0;
     }
@@ -1705,6 +1733,11 @@ static MODCMD_FUNC(cmd_svsjoin)
        return 0;
     }
 
+    if (IsLocal(target)) {
+       reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSJOIN");
+       return 0;
+    }
+
     if (!(channel = GetChannel(argv[2]))) {
        channel = AddChannel(argv[2], now, NULL, NULL, NULL);
     }
@@ -1726,6 +1759,12 @@ static MODCMD_FUNC(cmd_svsnick)
        reply("MSG_NICK_UNKNOWN", argv[1]);
        return 0;
     }
+
+    if (IsLocal(target)) {
+       reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSNICK");
+       return 0;
+    }
+
     if(!is_valid_nick(argv[2])) {
        reply("OMSG_BAD_SVSNICK", argv[2]);
        return 0;
@@ -1951,6 +1990,11 @@ static MODCMD_FUNC(cmd_svspart)
        return 0;
     }
 
+    if (IsLocal(target)) {
+       reply("OSMSG_BAD_SVSCMDTARGET", argv[1], "SVSPART");
+       return 0;
+    }
+
     if (!GetUserMode(target_channel, target)) {
         reply("OSMSG_NOT_ON_CHANNEL", cmd->parent->bot->nick, target_channel->name);
         return 0;
@@ -2174,6 +2218,28 @@ static MODCMD_FUNC(cmd_whois)
     if(target->mark) {
         reply("OSMSG_WHOIS_MARK", target->mark);
     }
+    if(target->marks) {
+        char markbuf[MAXLEN] = "";
+        unsigned int ii = 0;
+
+        string_list_sort(user->marks);
+
+        for (ii=0; ii<user->marks->used; ii++)
+        {
+            if (markbuf[0] && strlen(markbuf) + strlen(user->marks->list[ii]) + 4 > 70) {
+                reply("OSMSG_WHOIS_MARKS", markbuf);
+                memset(&markbuf, 0, MAXLEN);
+            }
+
+            if (markbuf[0])
+                strcat(markbuf, ", ");
+            strcat(markbuf, user->marks->list[ii]);
+        }
+
+        if (markbuf[0])
+            reply("OSMSG_WHOIS_MARKS", markbuf);
+    }
+
     reply("OSMSG_WHOIS_NO_NOTICE", target->no_notice ? "YES":"NO");
   
     if (target->modes) {
@@ -2528,10 +2594,13 @@ static MODCMD_FUNC(cmd_stats_alerts) {
         case REACT_GLINE: reaction = "gline"; break;
         case REACT_TRACK: reaction = "track"; break;
         case REACT_SHUN: reaction = "shun"; break;
+        case REACT_TEMPSHUN: reaction = "tempshun"; break;
         case REACT_SVSJOIN: reaction = "svsjoin"; break;
         case REACT_SVSPART: reaction = "svspart"; break;
         case REACT_VERSION: reaction = "version"; break;
         case REACT_MARK: reaction = "mark"; break;
+        case REACT_NOTICEUSER: reaction = "noticeuser"; break;
+        case REACT_MSGUSER: reaction = "msguser"; break;
         default: reaction = "<unknown>"; break;
         }
         reply("OSMSG_ALERT_IS", iter_key(it), reaction, alert->owner);
@@ -2915,7 +2984,7 @@ opserv_channel_check(struct chanNode *newchan, UNUSED_ARG(void *extra))
 }
 
 static void
-opserv_channel_delete(struct chanNode *chan)
+opserv_channel_delete(struct chanNode *chan, UNUSED_ARG(void *extra))
 {
     timeq_del(0, opserv_part_channel, chan, TIMEQ_IGNORE_WHEN);
 }
@@ -2955,7 +3024,9 @@ opserv_join_check(struct modeNode *mNode, UNUSED_ARG(void *extra))
     if (IsService(user))
         return 0;
 
-    dict_foreach(opserv_channel_alerts, alert_check_user, user);
+    /* Check for alerts, and stop if we find one that kills them. */
+    if (dict_foreach(opserv_user_alerts, alert_check_user, user))
+        return 1;
 
     if (opserv && channel->bad_channel) {
         opserv_debug("Found $b%s$b in bad-word channel $b%s$b; removing the user.", user->nick, channel->name);
@@ -4751,7 +4822,7 @@ add_gag_helper(const char *key, void *data, UNUSED_ARG(void *extra))
 }
 
 static struct opserv_user_alert *
-opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_reaction reaction, const char *text_discrim, int last, int expire)
+opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_reaction reaction, const char *text_discrim, int last, int expire, const char *action)
 {
     unsigned int wordc;
     char *wordv[MAXNUMPARAMS], *discrim_copy;
@@ -4768,7 +4839,7 @@ opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_react
     alert->last = last;
     discrim_copy = strdup(text_discrim); /* save a copy of the discrim */
     wordc = split_line(discrim_copy, false, ArrayLength(wordv), wordv);
-    alert->discrim = opserv_discrim_create(req, opserv, wordc, wordv, 0);
+    alert->discrim = opserv_discrim_create(req, opserv, wordc, wordv, 0, action);
     alert->expire = expire;
     /* Check for missing required criteria or broken records */
     if (!alert->discrim || (reaction==REACT_SVSJOIN && !alert->discrim->chantarget) ||
@@ -4856,6 +4927,8 @@ add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra))
         reaction = REACT_TRACK;
     else if (!irccasecmp(react, "shun"))
         reaction = REACT_SHUN;
+    else if (!irccasecmp(react, "tempshun"))
+        reaction = REACT_TEMPSHUN;
     else if (!irccasecmp(react, "svsjoin"))
         reaction = REACT_SVSJOIN;
     else if (!irccasecmp(react, "svspart"))
@@ -4864,11 +4937,15 @@ add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra))
         reaction = REACT_VERSION;
     else if (!irccasecmp(react, "mark"))
         reaction = REACT_MARK;
+    else if (!irccasecmp(react, "noticeuser"))
+        reaction = REACT_NOTICEUSER;
+    else if (!irccasecmp(react, "msguser"))
+        reaction = REACT_MSGUSER;
     else {
         log_module(OS_LOG, LOG_ERROR, "Invalid reaction %s for alert %s.", react, key);
         return 0;
     }
-    alert = opserv_add_user_alert(opserv, key, reaction, discrim, last, expire);
+    alert = opserv_add_user_alert(opserv, key, reaction, discrim, last, expire, react);
     if (!alert) {
         log_module(OS_LOG, LOG_ERROR, "Unable to create alert %s from database.", key);
         return 0;
@@ -5147,10 +5224,13 @@ opserv_saxdb_write(struct saxdb_context *ctx)
             case REACT_GLINE: reaction = "gline"; break;
             case REACT_TRACK: reaction = "track"; break;
             case REACT_SHUN: reaction = "shun"; break;
+            case REACT_TEMPSHUN: reaction = "tempshun"; break;
             case REACT_SVSJOIN: reaction = "svsjoin"; break;
             case REACT_SVSPART: reaction = "svspart"; break;
             case REACT_VERSION: reaction = "version"; break;
             case REACT_MARK: reaction = "mark"; break;
+            case REACT_NOTICEUSER: reaction = "noticeuser"; break;
+            case REACT_MSGUSER: reaction = "msguser"; break;
             default:
                 reaction = NULL;
                 log_module(OS_LOG, LOG_ERROR, "Invalid reaction type %d for alert %s (while writing database).", alert->reaction, iter_key(it));
@@ -5252,7 +5332,7 @@ static MODCMD_FUNC(cmd_settime)
 }
 
 static discrim_t
-opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel)
+opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[], int allow_channel, const char *action)
 {
     unsigned int i, j;
     discrim_t discrim;
@@ -5360,6 +5440,10 @@ opserv_discrim_create(struct userNode *user, struct userNode *bot, unsigned int
             goto fail;
         }
     } else if (irccasecmp(argv[i], "mark") == 0) {
+        if (irccasecmp(action, "mark")) {
+            send_message(user, bot, "OSMSG_MARK_NOTMARKED");
+            goto fail;
+        }
         if(!is_valid_mark(argv[i+1])) {
             send_message(user, bot, "OSMSG_MARK_INVALID");
             goto fail;
@@ -5647,6 +5731,20 @@ discrim_match(discrim_t discrim, struct userNode *user)
 {
     unsigned int level, i;
     char *scmp=NULL, *dcmp=NULL;
+    int markmatched = 0;
+
+    if (discrim->mask_mark)
+    {
+        unsigned int ii = 0;
+
+        if (user->mark && match_ircglob(user->mark, discrim->mask_mark))
+            markmatched = 1;
+
+        if (user->marks)
+            for (ii=0; ii<user->marks->used; ii++)
+                if (match_ircglob(user->marks->list[ii], discrim->mask_mark))
+                    markmatched = 1;
+    }
 
     if ((user->timestamp < discrim->min_ts)
         || (user->timestamp > discrim->max_ts)
@@ -5657,7 +5755,7 @@ discrim_match(discrim_t discrim, struct userNode *user)
         || (discrim->info_space == 0 && user->info[0] == ' ')
         || (discrim->info_space == 1 && user->info[0] != ' ')
         || (discrim->server && !match_ircglob(user->uplink->name, discrim->server))
-        || (discrim->mask_mark && (!user->mark || !match_ircglob(user->mark, discrim->mask_mark)))
+        || (discrim->mask_mark && !markmatched)
         || (discrim->accountmask && (!user->handle_info || !match_ircglob(user->handle_info->handle, discrim->accountmask)))
         || (discrim->ip_mask_bits && !irc_check_mask(&user->ip, &discrim->ip_mask, discrim->ip_mask_bits))
         )
@@ -5715,46 +5813,80 @@ discrim_match(discrim_t discrim, struct userNode *user)
 
     if (discrim->modes) {
            unsigned int ii, matches = 0;
+        unsigned int negate = 0;
         for (ii = 0; ii < strlen(discrim->modes); ii++) {
             switch(discrim->modes[ii]) {
+                case '+':
+                    negate = 0;
+                    matches++;
+                    break;
+                case '-':
+                    negate = 1;
+                    matches++;
+                    break;
                 case 'O':
-                    if(IsOper(user)) matches++;
+                    if(IsOper(user) != 0 != negate) matches++;
                     break;
                 case 'o':
-                    if(IsOper(user)) matches++;
+                    if(IsOper(user) != 0 != negate) matches++;
                     break;
                 case 'i':
-                    if(IsInvisible(user)) matches++;
+                    if(IsInvisible(user) != 0 != negate) matches++;
                     break;
                 case 'w':
-                    if(IsWallOp(user)) matches++;
+                    if(IsWallOp(user) != 0 != negate) matches++;
                     break;
                 case 'd':
-                    if(IsDeaf(user)) matches++;
+                    if(IsDeaf(user) != 0 != negate) matches++;
                     break;
                 case 'k':
-                    if(IsService(user)) matches++;
+                    if(IsService(user) != 0 != negate) matches++;
                     break;
                 case 'g':
-                    if(IsGlobal(user)) matches++;
+                    if(IsGlobal(user) != 0 != negate) matches++;
                     break;
                 case 'h':
-                    if(IsSetHost(user)) matches++;
+                    if(IsSetHost(user) != 0 != negate) matches++;
                     break;
                 case 'B':
-                    if(IsBotM(user)) matches++;
+                    if(IsBotM(user) != 0 != negate) matches++;
                     break;
+                case 'p':
                 case 'n':
-                    if(IsHideChans(user)) matches++;
+                    if(IsHideChans(user) != 0 != negate) matches++;
                     break;
                 case 'I':
-                    if(IsHideIdle(user)) matches++;
+                    if(IsHideIdle(user) != 0 != negate) matches++;
                     break;
                 case 'X':
-                    if(IsXtraOp(user)) matches++;
+                    if(IsXtraOp(user) != 0 != negate) matches++;
                     break;
                 case 'x':
-                    if(IsHiddenHost(user)) matches++;
+                    if(IsHiddenHost(user) != 0 != negate) matches++;
+                    break;
+                case 'a':
+                    if(IsAdmin(user) != 0 != negate) matches++;
+                    break;
+                case 'z':
+                    if(IsSSL(user) != 0 != negate) matches++;
+                    break;
+                case 'D':
+                    if(IsPrivDeaf(user) != 0 != negate) matches++;
+                    break;
+                case 'R':
+                    if(IsAccountOnly(user) != 0 != negate) matches++;
+                    break;
+                case 'W':
+                    if(IsWhoisNotice(user) != 0 != negate) matches++;
+                    break;
+                case 'H':
+                    if(IsHideOper(user) != 0 != negate) matches++;
+                    break;
+                case 'L':
+                    if(IsHideOper(user) != 0 != negate) matches++;
+                    break;
+                case 'q':
+                    if(IsCommonChansOnly(user) != 0 != negate) matches++;
                     break;
             }
         }
@@ -5954,6 +6086,18 @@ trace_shun_func(struct userNode *match, void *extra)
     return 0;
 }
 
+static int
+trace_tempshun_func(struct userNode *match, void *extra)
+{
+  struct discrim_and_source *das = extra;
+
+  if (is_oper_victim(das->source, match, das->discrim->match_opers, 1) && is_trust_victim(match, das->discrim->match_trusted)) {
+    opserv_tempshun(match, das->source->handle_info->handle, das->discrim->reason);
+  }
+
+  return 0;
+}
+
 static int
 trace_kill_func(struct userNode *match, void *extra)
 {
@@ -6191,6 +6335,8 @@ static MODCMD_FUNC(cmd_trace)
         action = trace_gline_func;
     else if (!irccasecmp(argv[1], "shun"))
         action = trace_shun_func;
+    else if (!irccasecmp(argv[1], "tempshun"))
+        action = trace_tempshun_func;
     else if (!irccasecmp(argv[1], "kill"))
         action = trace_kill_func;
     else if (!irccasecmp(argv[1], "gag"))
@@ -6216,7 +6362,7 @@ static MODCMD_FUNC(cmd_trace)
     das.dict = NULL;
     das.source = user;
     das.destination = cmd->parent->bot;
-    das.discrim = opserv_discrim_create(user, cmd->parent->bot, argc-2, argv+2, 1);
+    das.discrim = opserv_discrim_create(user, cmd->parent->bot, argc-2, argv+2, 1, argv[1]);
     if (!das.discrim)
         return 0;
 
@@ -6754,6 +6900,9 @@ alert_check_user(const char *key, void *data, void *extra)
     case REACT_SHUN:
         opserv_shun(user, alert->owner, alert->discrim->reason, alert->discrim->duration);
         return 1;
+    case REACT_TEMPSHUN:
+        opserv_tempshun(user, alert->owner, alert->discrim->reason);
+        return 1;
     case REACT_SVSJOIN:
         opserv_svsjoin(user, alert->owner, alert->discrim->reason, alert->discrim->chantarget, alert->discrim->checkrestrictions);
         break;
@@ -6784,12 +6933,18 @@ alert_check_user(const char *key, void *data, void *extra)
        add_track_user(user);
 #endif
        break;
+    case REACT_NOTICEUSER:
+        irc_notice_user(opserv, user, alert->discrim->reason);
+        break;
+    case REACT_MSGUSER:
+        irc_privmsg_user(opserv, user, alert->discrim->reason);
+        break;
     }
     return 0;
 }
 
 static void
-opserv_alert_check_account(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
+opserv_alert_check_account(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra))
 {
     dict_foreach(opserv_account_based_alerts, alert_check_user, user);
 }
@@ -6812,7 +6967,7 @@ opserv_alert_check_nick(struct userNode *user, UNUSED_ARG(const char *old_nick),
 }
 
 static void
-opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle))
+opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle), UNUSED_ARG(void *extra))
 {
     const char *type;
 
@@ -6961,6 +7116,8 @@ static MODCMD_FUNC(cmd_addalert)
 #endif
     } else if (!irccasecmp(argv[2], "shun"))
         reaction = REACT_SHUN;
+    else if(!irccasecmp(argv[2], "tempshun"))
+        reaction = REACT_TEMPSHUN;
     else if(!irccasecmp(argv[2], "svsjoin")) 
         reaction = REACT_SVSJOIN;
     else if(!irccasecmp(argv[2], "svspart")) 
@@ -6969,6 +7126,10 @@ static MODCMD_FUNC(cmd_addalert)
         reaction = REACT_VERSION;
     else if(!irccasecmp(argv[2], "mark"))
         reaction = REACT_MARK;
+    else if(!irccasecmp(argv[2], "noticeuser"))
+        reaction = REACT_NOTICEUSER;
+    else if(!irccasecmp(argv[2], "msguser"))
+        reaction = REACT_MSGUSER;
     else {
         reply("OSMSG_UNKNOWN_REACTION", argv[2]);
         return 0;
@@ -6978,7 +7139,7 @@ static MODCMD_FUNC(cmd_addalert)
         expire = now + ParseInterval(argv[4]);
 
     if (!svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY)
-        || !opserv_add_user_alert(user, name, reaction, unsplit_string(argv + (expire ? 5 : 3), argc - (expire ? 5 : 3), NULL), 0, expire)) {
+        || !opserv_add_user_alert(user, name, reaction, unsplit_string(argv + (expire ? 5 : 3), argc - (expire ? 5 : 3), NULL), 0, expire, argv[2])) {
         reply("OSMSG_ALERT_ADD_FAILED");
         return 0;
     }
@@ -7215,7 +7376,7 @@ opserv_db_init(void) {
 }
 
 static void
-opserv_db_cleanup(void)
+opserv_db_cleanup(UNUSED_ARG(void* extra))
 {
     unsigned int nn;
 
@@ -7253,9 +7414,12 @@ init_opserv(const char *nick)
     opserv_define_func("ACCESS", cmd_access, 0, 0, 0);
     opserv_define_func("ADDALERT", cmd_addalert, 800, 0, 4);
     opserv_define_func("ADDALERT NOTICE", NULL, 0, 0, 0);
+    opserv_define_func("ADDALERT NOTICEUSER", NULL, 0, 0, 0);
+    opserv_define_func("ADDALERT MSGUSER", NULL, 0, 0, 0);
     opserv_define_func("ADDALERT SILENT", NULL, 900, 0, 0);
     opserv_define_func("ADDALERT GLINE", NULL, 900, 0, 0);
     opserv_define_func("ADDALERT SHUN", NULL, 900, 0, 0);
+    opserv_define_func("ADDALERT TEMPSHUN", NULL, 900, 0, 0);
     opserv_define_func("ADDALERT TRACK", NULL, 900, 0, 0);
     opserv_define_func("ADDALERT KILL", NULL, 900, 0, 0);
     opserv_define_func("ADDALERT SVSJOIN", NULL, 999, 0, 0);
@@ -7369,6 +7533,7 @@ init_opserv(const char *nick)
     opserv_define_func("TRACE DOMAINS", NULL, 0, 0, 0);
     opserv_define_func("TRACE GLINE", NULL, 600, 0, 0);
     opserv_define_func("TRACE SHUN", NULL, 600, 0, 0);
+    opserv_define_func("TRACE TEMPSHUN", NULL, 600, 0, 0);
     opserv_define_func("TRACE GAG", NULL, 600, 0, 0);
     opserv_define_func("TRACE KILL", NULL, 600, 0, 0);
     opserv_define_func("TRACE VERSION", NULL, 999, 0, 0);
@@ -7401,10 +7566,10 @@ init_opserv(const char *nick)
     reg_nick_change_func(opserv_alert_check_nick, NULL);
     reg_del_user_func(opserv_user_cleanup, NULL);
     reg_new_channel_func(opserv_channel_check, NULL); 
-    reg_del_channel_func(opserv_channel_delete);
+    reg_del_channel_func(opserv_channel_delete, NULL);
     reg_join_func(opserv_join_check, NULL);
-    reg_auth_func(opserv_staff_alert);
-    reg_auth_func(opserv_alert_check_account);
+    reg_auth_func(opserv_staff_alert, NULL);
+    reg_auth_func(opserv_alert_check_account, NULL);
     reg_notice_func(opserv, opserv_notice_handler);
 
     opserv_db_init();
@@ -7422,6 +7587,6 @@ init_opserv(const char *nick)
     /* start the karma timer, using the saved one if available */
     routing_karma_timer(dict_find(opserv_routing_plan_options, "KARMA_TIMER", NULL));
 
-    reg_exit_func(opserv_db_cleanup);
+    reg_exit_func(opserv_db_cleanup, NULL);
     message_register_table(msgtab);
 }