X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/a32da4c70ca85b879f8162469ae37ffeca500b99..2f61d1d75ac52f239e760ecea02332eedc4682bd:/src/opserv.c diff --git a/src/opserv.c b/src/opserv.c index 49c2819..cea9ca1 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -1,7 +1,7 @@ /* opserv.c - IRC Operator assistance service * Copyright 2000-2004 srvx Development Team * - * This file is part of srvx. + * This file is part of x3. * * srvx is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include "opserv.h" #include "timeq.h" #include "saxdb.h" +#include "shun.h" #ifdef HAVE_SYS_TIMES_H #include @@ -36,6 +37,9 @@ #ifdef HAVE_ARPA_INET_H #include #endif +#ifdef HAVE_REGEX_H +#include +#endif #define OPSERV_CONF_NAME "services/opserv" @@ -74,23 +78,31 @@ #define KEY_STAFF_AUTH_CHANNEL_MODES "staff_auth_channel_modes" #define KEY_CLONE_GLINE_DURATION "clone_gline_duration" #define KEY_BLOCK_GLINE_DURATION "block_gline_duration" +#define KEY_BLOCK_SHUN_DURATION "block_shun_duration" #define KEY_ISSUER "issuer" #define KEY_ISSUED "issued" +#define KEY_ADMIN_LEVEL "admin_level" -#define IDENT_FORMAT "%s [%s@%s/%s]" -#define IDENT_DATA(user) user->nick, user->ident, user->hostname, inet_ntoa(user->ip) -#define MAX_CHANNELS_WHOIS 50 +#define IDENT_FORMAT "%s [%s@%s/%s]" +#define IDENT_DATA(user) user->nick, user->ident, user->hostname, irc_ntoa(&user->ip) +#define MAX_CHANNELS_WHOIS 50 #define OSMSG_PART_REASON "%s has no reason." #define OSMSG_KICK_REQUESTED "Kick requested by %s." #define OSMSG_KILL_REQUESTED "Kill requested by %s." #define OSMSG_GAG_REQUESTED "Gag requested by %s." static const struct message_entry msgtab[] = { + { "OSMSG_BAR", "----------------------------------------" }, { "OSMSG_USER_ACCESS_IS", "$b%s$b (account $b%s$b) has %d access." }, { "OSMSG_LEVEL_TOO_LOW", "You lack sufficient access to use this command." }, { "OSMSG_NEED_CHANNEL", "You must specify a channel for $b%s$b." }, { "OSMSG_INVALID_IRCMASK", "$b%s$b is an invalid IRC hostmask." }, { "OSMSG_ADDED_BAN", "I have banned $b%s$b from $b%s$b." }, + { "OSMSG_SHUN_ISSUED", "Shun issued for $b%s$b." }, + { "OSMSG_SHUN_REMOVED", "Shun removed for $b%s$b." }, + { "OSMSG_SHUN_FORCE_REMOVED", "Unknown/expired Shun removed for $b%s$b." }, + { "OSMSG_SHUN_ONE_REFRESHED", "All Shuns resent to $b%s$b." }, + { "OSMSG_SHUN_REFRESHED", "All Shuns refreshed." }, { "OSMSG_GLINE_ISSUED", "G-line issued for $b%s$b." }, { "OSMSG_GLINE_REMOVED", "G-line removed for $b%s$b." }, { "OSMSG_GLINE_FORCE_REMOVED", "Unknown/expired G-line removed for $b%s$b." }, @@ -155,12 +167,17 @@ static const struct message_entry msgtab[] = { { "OSMSG_BADWORD_LIST", "Bad words: %s" }, { "OSMSG_EXEMPTED_LIST", "Exempted channels: %s" }, { "OSMSG_GLINE_COUNT", "There are %d glines active on the network." }, + { "OSMSG_SHUN_COUNT", "There are %d shuns active on the network." }, { "OSMSG_LINKS_SERVER", "%s%s (%u clients; %s)" }, { "OSMSG_MAX_CLIENTS", "Max clients: %d at %s" }, { "OSMSG_NETWORK_INFO", "Total users: %d (%d invisible, %d opers)" }, { "OSMSG_RESERVED_LIST", "List of reserved nicks:" }, - { "OSMSG_TRUSTED_LIST", "List of trusted hosts:" }, - { "OSMSG_HOST_IS_TRUSTED", "%s (%s; set %s ago by %s; expires %s: %s)" }, + { "OSMSG_TRUSTED_LIST", "$bTrusted Hosts$b" }, + { "OSMSG_TRUSTED_LIST_HEADER", "IP Address Limit By Time" }, + { "OSMSG_HOST_IS_TRUSTED", "%-15s %-5s %-10s set %s ago, expires %s" }, + { "OSMSG_HOST_IS_TRUSTED_DESC", " Reason: %s" }, + { "OSMSG_TRUSTED_LIST_BAR", "----------------------------------------" }, + { "OSMSG_TRUSTED_LIST_END", "----------End of Trusted Hosts----------" }, { "OSMSG_HOST_NOT_TRUSTED", "%s does not have a special trust." }, { "OSMSG_UPTIME_STATS", "Uptime: %s (%u lines processed, CPU time %.2fu/%.2fs)" }, { "OSMSG_LINE_DUMPED", "Raw line sent." }, @@ -196,11 +213,18 @@ static const struct message_entry msgtab[] = { { "OSMSG_SETTIME_SUCCESS", "Set time for servers named like $b%s$b." }, { "OSMSG_BAD_ACTION", "Unrecognized trace action $b%s$b." }, { "OSMSG_USER_SEARCH_RESULTS", "The following users were found:" }, + { "OSMSG_USER_SEARCH_HEADER", "Nick User@Host (Account)" }, + { "OSMSG_USER_SEARCH_BAR", "-------------------------------------------" }, + { "OSMSG_USER_SEARCH_COUNT", "There were %4u matches" }, + { "OSMSG_USER_SEARCH_COUNT_BAR", "------------ Found %4u matches -----------" }, { "OSMSG_CHANNEL_SEARCH_RESULTS", "The following channels were found:" }, { "OSMSG_GLINE_SEARCH_RESULTS", "The following glines were found:" }, + { "OSMSG_SHUN_SEARCH_RESULTS", "The following shun were found:" }, { "OSMSG_LOG_SEARCH_RESULTS", "The following log entries were found:" }, { "OSMSG_GSYNC_RUNNING", "Synchronizing glines from %s." }, + { "OSMSG_SSYNC_RUNNING", "Synchronizing shuns from %s." }, { "OSMSG_GTRACE_FORMAT", "%s (issued %s by %s, expires %s): %s" }, + { "OSMSG_STRACE_FORMAT", "%s (issued %s by %s, expires %s): %s" }, { "OSMSG_GAG_APPLIED", "Gagged $b%s$b, affecting %d users." }, { "OSMSG_GAG_ADDED", "Gagged $b%s$b." }, { "OSMSG_REDUNDANT_GAG", "Gag $b%s$b is redundant." }, @@ -214,8 +238,12 @@ static const struct message_entry msgtab[] = { { "OSMSG_ADDED_ALERT", "Added alert named $b%s$b." }, { "OSMSG_REMOVED_ALERT", "Removed alert named $b%s$b." }, { "OSMSG_NO_SUCH_ALERT", "No alert named $b%s$b could be found." }, - { "OSMSG_ALERT_IS", "%s (by %s, reaction %s): %s" }, - { "OSMSG_ALERTS_LIST", "Current $O alerts:" }, + { "OSMSG_ALERTS_LIST", "$bCurrent $O alerts$b" }, + { "OSMSG_ALERTS_BAR", "----------------------------------------------" }, + { "OSMSG_ALERTS_HEADER", "Name Action (by Oper)" }, + { "OSMSG_ALERTS_DESC", " Criteria: %s" }, + { "OSMSG_ALERT_IS", "$b%-20s$b %-6s (by %s)" }, + { "OSMSG_ALERT_END", "----------------End of Alerts-----------------" }, { "OSMSG_REHASH_COMPLETE", "Completed rehash of configuration database." }, { "OSMSG_REHASH_FAILED", "Rehash of configuration database failed, previous configuration is intact." }, { "OSMSG_REOPEN_COMPLETE", "Closed and reopened all log files." }, @@ -226,6 +254,7 @@ static const struct message_entry msgtab[] = { { "OSMSG_SERVER_JUPED", "Added new jupe server %s." }, { "OSMSG_SERVER_NOT_JUPE", "That server is not a juped server." }, { "OSMSG_SERVER_UNJUPED", "Server jupe removed." }, + /* { "OSMSG_WARN_ADDED", "Added channel activity warning for $b%s$b (%s)" }, { "OSMSG_WARN_EXISTS", "Channel activity warning for $b%s$b already exists." }, { "OSMSG_WARN_DELETED", "Removed channel activity warning for $b%s$b" }, @@ -233,6 +262,7 @@ static const struct message_entry msgtab[] = { { "OSMSG_WARN_LISTSTART", "Channel activity warnings:" }, { "OSMSG_WARN_LISTENTRY", "%s (%s)" }, { "OSMSG_WARN_LISTEND", "End of activity warning list." }, + */ { "OSMSG_UPLINK_CONNECTING", "Establishing connection with %s (%s:%d)." }, { "OSMSG_CURRENT_UPLINK", "$b%s$b is already the current uplink." }, { "OSMSG_INVALID_UPLINK", "$b%s$b is not a valid uplink name." }, @@ -240,6 +270,7 @@ static const struct message_entry msgtab[] = { { "OSMSG_UPLINK_START", "Uplink $b%s$b:" }, { "OSMSG_UPLINK_ADDRESS", "Address: %s:%d" }, { "OSMSG_STUPID_GLINE", "Gline %s? Now $bthat$b would be smooth." }, + { "OSMSG_STUPID_SHUN", "Shun %s? Now $bthat$b would be smooth." }, { "OSMSG_ACCOUNTMASK_AUTHED", "Invalid criteria: it is impossible to match an account mask but not be authed" }, { "OSMSG_CHANINFO_HEADER", "%s Information" }, { "OSMSG_CHANINFO_TIMESTAMP", "Created on: %a %b %d %H:%M:%S %Y (%s)" }, @@ -254,16 +285,18 @@ static const struct message_entry msgtab[] = { { "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" }, + { "OSMSG_INVALID_REGEX", "Invalid regex: %s: %s (%d)" }, { NULL, NULL } }; -#define OPSERV_SYNTAX() svccmd_send_help(user, opserv, cmd) +#define OPSERV_SYNTAX() svccmd_send_help_brief(user, opserv, cmd) typedef int (*discrim_search_func)(struct userNode *match, void *extra); struct userNode *opserv; +static struct service *opserv_service; -static dict_t opserv_chan_warn; /* data is char* */ +/*static dict_t opserv_chan_warn; */ /* data is char* */ static dict_t opserv_reserved_nick_dict; /* data is struct userNode* */ static struct string_list *opserv_bad_words; static dict_t opserv_exempt_channels; /* data is not used */ @@ -286,9 +319,11 @@ static struct { unsigned long untrusted_max; unsigned long clone_gline_duration; unsigned long block_gline_duration; + unsigned long block_shun_duration; unsigned long purge_lock_delay; unsigned long join_flood_moderate; unsigned long join_flood_moderate_threshold; + unsigned long admin_level; } opserv_conf; struct trusted_host { @@ -325,24 +360,30 @@ opserv_free_hostinfo(void *data) typedef struct opservDiscrim { struct chanNode *channel; - char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *ip_mask_str, *reason, *accountmask; - unsigned long limit, ip_mask; - struct in_addr ip_addr; + char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *reason, *accountmask; + irc_in_addr_t ip_mask; + unsigned long limit; + time_t min_ts, max_ts; + regex_t regex_nick, regex_ident, regex_host, regex_info; + unsigned int has_regex_nick : 1, has_regex_ident : 1, has_regex_host : 1, has_regex_info : 1; unsigned int min_level, max_level, domain_depth, duration, min_clones, min_channels, max_channels; + unsigned char ip_mask_bits; unsigned int match_opers : 1, option_log : 1; unsigned int chan_req_modes : 2, chan_no_modes : 2; int authed : 2, info_space : 2; - time_t min_ts, max_ts; + unsigned int intra_scmp : 2, intra_dcmp : 2; + unsigned int use_regex : 1; } *discrim_t; struct discrim_and_source { discrim_t discrim; struct userNode *source; + struct userNode *destination; dict_t dict; unsigned int disp_limit; }; -static discrim_t opserv_discrim_create(struct userNode *user, 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); 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); @@ -350,7 +391,9 @@ static int ungag_helper_func(struct userNode *match, void *extra); typedef enum { REACT_NOTICE, REACT_KILL, - REACT_GLINE + REACT_SILENT, + REACT_GLINE, + REACT_SHUN } opserv_alert_reaction; struct opserv_user_alert { @@ -370,6 +413,14 @@ opserv_free_user_alert(void *data) free(alert->owner); free(alert->text_discrim); free(alert->split_discrim); + if(alert->discrim->has_regex_nick) + regfree(&alert->discrim->regex_nick); + if(alert->discrim->has_regex_ident) + regfree(&alert->discrim->regex_ident); + if(alert->discrim->has_regex_host) + regfree(&alert->discrim->regex_host); + if(alert->discrim->has_regex_info) + regfree(&alert->discrim->regex_info); free(alert->discrim->reason); free(alert->discrim); free(alert); @@ -395,7 +446,7 @@ static MODCMD_FUNC(cmd_access) } if (!(hi = modcmd_get_handle_info(user, target))) return 0; - res = (argc > 2) ? oper_try_set_access(user, cmd->parent->bot, hi, strtoul(argv[2], NULL, 0)) : 0; + res = (argc > 2) ? oper_try_set_access(user, opserv_service->bot, hi, strtoul(argv[2], NULL, 0)) : 0; reply("OSMSG_USER_ACCESS_IS", target, hi->handle, hi->opserv_level); return res; } @@ -413,8 +464,8 @@ static MODCMD_FUNC(cmd_ban) else if ((victim = GetUserH(argv[1]))) change.args[0].u.hostmask = generate_hostmask(victim, 0); else { - reply("OSMSG_INVALID_IRCMASK", argv[1]); - return 0; + reply("OSMSG_INVALID_IRCMASK", argv[1]); + return 0; } modcmd_chanmode_announce(&change); reply("OSMSG_ADDED_BAN", change.args[0].u.hostmask, channel->name); @@ -445,17 +496,17 @@ static MODCMD_FUNC(cmd_chaninfo) strftime(buffer, sizeof(buffer), fmt, gmtime(&channel->topic_time)); send_message_type(4, user, cmd->parent->bot, buffer, channel->topic_nick, channel->topic); } else { - irc_fetchtopic(cmd->parent->bot, channel->name); - reply("OSMSG_CHANINFO_TOPIC_UNKNOWN"); + irc_fetchtopic(cmd->parent->bot, channel->name); + reply("OSMSG_CHANINFO_TOPIC_UNKNOWN"); } if (channel->banlist.used) { - reply("OSMSG_CHANINFO_BAN_COUNT", channel->banlist.used); + reply("OSMSG_CHANINFO_BAN_COUNT", channel->banlist.used); fmt = user_find_message(user, "OSMSG_CHANINFO_BAN"); - for (n = 0; n < channel->banlist.used; n++) { - ban = channel->banlist.list[n]; - strftime(buffer, sizeof(buffer), fmt, localtime(&ban->set)); - send_message_type(4, user, cmd->parent->bot, buffer, ban->ban, ban->who); - } + for (n = 0; n < channel->banlist.used; n++) { + ban = channel->banlist.list[n]; + strftime(buffer, sizeof(buffer), fmt, localtime(&ban->set)); + 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); @@ -473,9 +524,13 @@ static MODCMD_FUNC(cmd_chaninfo) } reply("OSMSG_CHANINFO_USER_COUNT", channel->members.used); for (n=0; nmembers.used; n++) { - moden = channel->members.list[n]; - 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); + moden = channel->members.list[n]; + if (moden->modes & MODE_CHANOP) { + if (moden->oplevel >= 0) + send_message_type(4, user, cmd->parent->bot, " @%s:%d (%s@%s)", moden->user->nick, moden->oplevel, moden->user->ident, moden->user->hostname); + else + send_message_type(4, user, cmd->parent->bot, " @%s (%s@%s)", moden->user->nick, moden->user->ident, moden->user->hostname); + } } for (n=0; nmembers.used; n++) { moden = channel->members.list[n]; @@ -483,25 +538,27 @@ static MODCMD_FUNC(cmd_chaninfo) send_message_type(4, user, cmd->parent->bot, " %s%s (%s@%s)", "%", moden->user->nick, moden->user->ident, moden->user->hostname); } for (n=0; nmembers.used; n++) { - moden = channel->members.list[n]; - if ((moden->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) == MODE_VOICE) + moden = channel->members.list[n]; + 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; nmembers.used; n++) { - moden = channel->members.list[n]; - if ((moden->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) == 0) + moden = channel->members.list[n]; + 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; } -static MODCMD_FUNC(cmd_warn) +/* This command has been replaced by 'alert notice channel #foo' */ +/* +static MODCMD_FUNC(cmd_warn) { char *reason, *message; if (!IsChannelName(argv[1])) { - reply("OSMSG_NEED_CHANNEL", argv[0]); - return 0; + reply("OSMSG_NEED_CHANNEL", argv[0]); + return 0; } reason = dict_find(opserv_chan_warn, argv[1], NULL); if (reason) { @@ -526,7 +583,7 @@ static MODCMD_FUNC(cmd_unwarn) { if ((argc < 2) || !IsChannelName(argv[1])) { reply("OSMSG_NEED_CHANNEL", argv[0]); - return 0; + return 0; } if (!dict_remove(opserv_chan_warn, argv[1])) { reply("OSMSG_WARN_NOEXIST", argv[1]); @@ -535,6 +592,7 @@ static MODCMD_FUNC(cmd_unwarn) reply("OSMSG_WARN_DELETED", argv[1]); return 1; } +*/ static MODCMD_FUNC(cmd_clearbans) { @@ -544,9 +602,11 @@ static MODCMD_FUNC(cmd_clearbans) change = mod_chanmode_alloc(channel->banlist.used); for (ii=0; iibanlist.used; ii++) { change->args[ii].mode = MODE_REMOVE | MODE_BAN; - change->args[ii].u.hostmask = channel->banlist.list[ii]->ban; + change->args[ii].u.hostmask = strdup(channel->banlist.list[ii]->ban); } modcmd_chanmode_announce(change); + for (ii=0; iiargc; ++ii) + free((char*)change->args[ii].u.hostmask); mod_chanmode_free(change); reply("OSMSG_CLEARBANS_DONE", channel->name); return 1; @@ -557,7 +617,7 @@ static MODCMD_FUNC(cmd_clearmodes) struct mod_chanmode change; if (!channel->modes) { - reply("OSMSG_NO_CHANNEL_MODES", channel->name); + reply("OSMSG_NO_CHANNEL_MODES", channel->name); return 0; } mod_chanmode_init(&change); @@ -576,7 +636,7 @@ static MODCMD_FUNC(cmd_deop) for (arg = 1, count = 0; arg < argc; ++arg) { struct userNode *victim = GetUserH(argv[arg]); struct modeNode *mn; - if (!victim || IsService(victim) + if (!victim || IsService(victim) || !(mn = GetUserMode(channel, victim)) || !(mn->modes & MODE_CHANOP)) continue; @@ -606,7 +666,7 @@ static MODCMD_FUNC(cmd_dehop) || !(mn->modes & MODE_HALFOP)) continue; change->args[count].mode = MODE_REMOVE | MODE_HALFOP; - change->args[count++].member = mn; + change->args[count++].u.member = mn; } if (count) { change->argc = count; @@ -624,8 +684,8 @@ static MODCMD_FUNC(cmd_deopall) 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_CHANOP)) + struct modeNode *mn = channel->members.list[ii]; + if (IsService(mn->user) || !(mn->modes & MODE_CHANOP)) continue; change->args[count].mode = MODE_REMOVE | MODE_CHANOP; change->args[count++].u.member = mn; @@ -650,7 +710,7 @@ static MODCMD_FUNC(cmd_dehopall) if (IsService(mn->user) || !(mn->modes & MODE_HALFOP)) continue; change->args[count].mode = MODE_REMOVE | MODE_HALFOP; - change->args[count++].member = mn; + change->args[count++].u.member = mn; } if (count) { change->argc = count; @@ -666,9 +726,9 @@ static MODCMD_FUNC(cmd_rehash) extern char *services_config; if (conf_read(services_config)) - reply("OSMSG_REHASH_COMPLETE"); + reply("OSMSG_REHASH_COMPLETE"); else - reply("OSMSG_REHASH_FAILED"); + reply("OSMSG_REHASH_FAILED"); return 1; } @@ -753,14 +813,14 @@ static MODCMD_FUNC(cmd_jump) target = unsplit_string(argv+1, argc-1, NULL); if (!strcmp(cManager.uplink->name, target)) { - reply("OSMSG_CURRENT_UPLINK", cManager.uplink->name); - return 0; + reply("OSMSG_CURRENT_UPLINK", cManager.uplink->name); + return 0; } uplink = uplink_find(target); if (!uplink) { - reply("OSMSG_INVALID_UPLINK", target); - return 0; + reply("OSMSG_INVALID_UPLINK", target); + return 0; } if (uplink->flags & UPLINK_UNAVAILABLE) { reply("OSMSG_UPLINK_DISABLED", uplink->name); @@ -811,17 +871,16 @@ static MODCMD_FUNC(cmd_restart) } static struct gline * -opserv_block(struct userNode *target, char *src_handle, char *reason, unsigned long duration) +opserv_block(struct userNode *target, char *src_handle, char *reason, unsigned long duration, int silent) { - char *mask; - mask = alloca(MAXLEN); - snprintf(mask, MAXLEN, "*@%s", target->hostname); - if (!reason) { - reason = alloca(MAXLEN); - snprintf(reason, MAXLEN, "G-line requested by %s.", src_handle); - } - if (!duration) duration = opserv_conf.block_gline_duration; - return gline_add(src_handle, mask, duration, reason, now, 1); + char mask[IRC_NTOP_MAX_SIZE+3] = { '*', '@', '\0' }; + irc_ntop(mask + 2, sizeof(mask) - 2, &target->ip); + if (!reason) + snprintf(reason = alloca(MAXLEN), MAXLEN, + "G-line requested by %s.", src_handle); + if (!duration) + duration = opserv_conf.block_gline_duration; + return gline_add(src_handle, mask, duration, reason, now, 1, silent ? 1 : 0); } static MODCMD_FUNC(cmd_block) @@ -832,15 +891,15 @@ static MODCMD_FUNC(cmd_block) target = GetUserH(argv[1]); if (!target) { - reply("MSG_NICK_UNKNOWN", argv[1]); - return 0; + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; } if (IsService(target)) { - reply("MSG_SERVICE_IMMUNE", target->nick); - return 0; + reply("MSG_SERVICE_IMMUNE", target->nick); + return 0; } reason = (argc > 2) ? unsplit_string(argv+2, argc-2, NULL) : NULL; - gline = opserv_block(target, user->handle_info->handle, reason, 0); + gline = opserv_block(target, user->handle_info->handle, reason, 0, 0); reply("OSMSG_GLINE_ISSUED", gline->target); return 1; } @@ -853,8 +912,8 @@ static MODCMD_FUNC(cmd_gline) reason = unsplit_string(argv+3, argc-3, NULL); if (!is_gline(argv[1]) && !IsChannelName(argv[1]) && (argv[1][0] != '&')) { - reply("MSG_INVALID_GLINE", argv[1]); - return 0; + reply("MSG_INVALID_GLINE", argv[1]); + return 0; } if (!argv[1][strspn(argv[1], "#&*?@.")] && (strlen(argv[1]) < 10)) { reply("OSMSG_STUPID_GLINE", argv[1]); @@ -865,7 +924,7 @@ static MODCMD_FUNC(cmd_gline) reply("MSG_INVALID_DURATION", argv[2]); return 0; } - gline = gline_add(user->handle_info->handle, argv[1], duration, reason, now, 1); + gline = gline_add(user->handle_info->handle, argv[1], duration, reason, now, 1, 0); reply("OSMSG_GLINE_ISSUED", gline->target); return 1; } @@ -905,6 +964,101 @@ static MODCMD_FUNC(cmd_refreshg) return 1; } +static struct shun * +opserv_shun(struct userNode *target, char *src_handle, char *reason, unsigned long duration) +{ + char *mask; + mask = alloca(MAXLEN); + snprintf(mask, MAXLEN, "*@%s", target->hostname); + if (!reason) { + reason = alloca(MAXLEN); + snprintf(reason, MAXLEN, "Shun requested by %s.", src_handle); + } + if (!duration) duration = opserv_conf.block_shun_duration; + return shun_add(src_handle, mask, duration, reason, now, 1); +} + +static MODCMD_FUNC(cmd_sblock) +{ + struct userNode *target; + struct shun *shun; + char *reason; + + target = GetUserH(argv[1]); + if (!target) { + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; + } + if (IsService(target)) { + reply("MSG_SERVICE_IMMUNE", target->nick); + return 0; + } + reason = (argc > 2) ? unsplit_string(argv+2, argc-2, NULL) : NULL; + shun = opserv_shun(target, user->handle_info->handle, reason, 0); + reply("OSMSG_SHUN_ISSUED", shun->target); + return 1; +} + +static MODCMD_FUNC(cmd_shun) +{ + unsigned long duration; + char *reason; + struct shun *shun; + + reason = unsplit_string(argv+3, argc-3, NULL); + if (!is_shun(argv[1]) && !IsChannelName(argv[1]) && (argv[1][0] != '&')) { + reply("MSG_INVALID_SHUN", argv[1]); + return 0; + } + if (!argv[1][strspn(argv[1], "#&*?@.")] && (strlen(argv[1]) < 10)) { + reply("OSMSG_STUPID_SHUN", argv[1]); + return 0; + } + duration = ParseInterval(argv[2]); + if (!duration) { + reply("MSG_INVALID_DURATION", argv[2]); + return 0; + } + shun = shun_add(user->handle_info->handle, argv[1], duration, reason, now, 1); + reply("OSMSG_SHUN_ISSUED", shun->target); + return 1; +} + +static MODCMD_FUNC(cmd_unshun) +{ + if (shun_remove(argv[1], 1)) + reply("OSMSG_SHUN_REMOVED", argv[1]); + else + reply("OSMSG_SHUN_FORCE_REMOVED", argv[1]); + return 1; +} + +static MODCMD_FUNC(cmd_refreshs) +{ + if (argc > 1) { + unsigned int count; + dict_iterator_t it; + struct server *srv; + + for (it=dict_first(servers), count=0; it; it=iter_next(it)) { + srv = iter_data(it); + if ((srv == self) || !match_ircglob(srv->name, argv[1])) + continue; + shun_refresh_server(srv); + reply("OSMSG_SHUNS_ONE_REFRESHED", srv->name); + count++; + } + if (!count) { + reply("MSG_SERVER_UNKNOWN", argv[1]); + return 0; + } + } else { + shun_refresh_all(); + reply("OSMSG_SHUNS_REFRESHED"); + } + return 1; +} + static void opserv_ison(struct userNode *tell, struct userNode *target, const char *message) { @@ -916,26 +1070,26 @@ opserv_ison(struct userNode *tell, struct userNode *target, const char *message) if (!maxlen) maxlen = MAX_LINE_SIZE; for (n=count=0; nchannels.used; n++) { - mn = target->channels.list[n]; - here_len = strlen(mn->channel->name); - if ((count + here_len + 4) > maxlen) { - buff[count] = 0; + mn = target->channels.list[n]; + here_len = strlen(mn->channel->name); + if ((count + here_len + 4) > maxlen) { + buff[count] = 0; send_message(tell, opserv, message, buff); - count = 0; - } - if (mn->modes & MODE_CHANOP) + count = 0; + } + if (mn->modes & MODE_CHANOP) buff[count++] = '@'; if (mn->modes & MODE_HALFOP) buff[count++] = '%'; - if (mn->modes & MODE_VOICE) + if (mn->modes & MODE_VOICE) buff[count++] = '+'; - memcpy(buff+count, mn->channel->name, here_len); - count += here_len; - buff[count++] = ' '; + memcpy(buff+count, mn->channel->name, here_len); + count += here_len; + buff[count++] = ' '; } if (count) { - buff[count] = 0; - send_message(tell, opserv, message, buff); + buff[count] = 0; + send_message(tell, opserv, message, buff); } } @@ -944,17 +1098,17 @@ static MODCMD_FUNC(cmd_inviteme) struct userNode *target; if (argc < 2) { - target = user; + target = user; } else { - target = GetUserH(argv[1]); - if (!target) { - reply("MSG_NICK_UNKNOWN", argv[1]); - return 0; - } + target = GetUserH(argv[1]); + if (!target) { + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; + } } if (opserv_conf.debug_channel == NULL) { - reply("OSMSG_NO_DEBUG_CHANNEL"); - return 0; + reply("OSMSG_NO_DEBUG_CHANNEL"); + return 0; } if (GetUserMode(opserv_conf.debug_channel, user)) { reply("OSMSG_ALREADY_THERE", opserv_conf.debug_channel->name); @@ -962,7 +1116,7 @@ static MODCMD_FUNC(cmd_inviteme) } irc_invite(cmd->parent->bot, target, opserv_conf.debug_channel); if (target != user) - reply("OSMSG_INVITE_DONE", target->nick, opserv_conf.debug_channel->name); + reply("OSMSG_INVITE_DONE", target->nick, opserv_conf.debug_channel->name); return 1; } @@ -1008,19 +1162,19 @@ static MODCMD_FUNC(cmd_kick) char *reason; if (argc < 3) { - reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); - sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); + reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); + sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); } else { - reason = unsplit_string(argv+2, argc-2, NULL); + reason = unsplit_string(argv+2, argc-2, NULL); } target = GetUserH(argv[1]); if (!target) { - reply("MSG_NICK_UNKNOWN", argv[1]); - return 0; + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; } if (!GetUserMode(channel, target)) { - reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); - return 0; + reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); + return 0; } KickChannelUser(target, channel, cmd->parent->bot, reason); return 1; @@ -1043,20 +1197,20 @@ static MODCMD_FUNC(cmd_kickall) modcmd_chanmode_announce(&change); } if (argc < 2) { - reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); - sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); + reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); + sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); } else { - reason = unsplit_string(argv+1, argc-1, NULL); + reason = unsplit_string(argv+1, argc-1, NULL); } limit = user->handle_info->opserv_level; for (n=channel->members.used; n>0;) { - mn = channel->members.list[--n]; - if (IsService(mn->user) - || (mn->user->handle_info - && (mn->user->handle_info->opserv_level >= limit))) { - continue; - } - KickChannelUser(mn->user, channel, bot, reason); + mn = channel->members.list[--n]; + if (IsService(mn->user) + || (mn->user->handle_info + && (mn->user->handle_info->opserv_level >= limit))) { + continue; + } + KickChannelUser(mn->user, channel, bot, reason); } if (!inchan) DelChannelUser(bot, channel, "My work here is done", 0); @@ -1072,19 +1226,19 @@ static MODCMD_FUNC(cmd_kickban) char *mask; if (argc == 2) { - reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); - sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); + reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); + sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); } else { - reason = unsplit_string(argv+2, argc-2, NULL); + reason = unsplit_string(argv+2, argc-2, NULL); } target = GetUserH(argv[1]); if (!target) { - reply("MSG_NICK_UNKNOWN", argv[1]); - return 0; + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; } if (!GetUserMode(channel, target)) { - reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); - return 0; + reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); + return 0; } mod_chanmode_init(&change); change.argc = 1; @@ -1120,21 +1274,21 @@ static MODCMD_FUNC(cmd_kickbanall) 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); + reason = alloca(strlen(OSMSG_KICK_REQUESTED)+strlen(user->nick)+1); + sprintf(reason, OSMSG_KICK_REQUESTED, user->nick); } else { - reason = unsplit_string(argv+1, argc-1, NULL); + reason = unsplit_string(argv+1, argc-1, NULL); } /* now kick them */ limit = user->handle_info->opserv_level; for (n=channel->members.used; n>0; ) { - mn = channel->members.list[--n]; - if (IsService(mn->user) - || (mn->user->handle_info - && (mn->user->handle_info->opserv_level >= limit))) { - continue; - } - KickChannelUser(mn->user, channel, bot, reason); + mn = channel->members.list[--n]; + if (IsService(mn->user) + || (mn->user->handle_info + && (mn->user->handle_info->opserv_level >= limit))) { + continue; + } + KickChannelUser(mn->user, channel, bot, reason); } if (!inchan) DelChannelUser(bot, channel, "My work here is done", 0); @@ -1215,7 +1369,7 @@ static MODCMD_FUNC(cmd_hop) if (mn->modes & MODE_HALFOP) continue; change->args[count].mode = MODE_HALFOP; - change->args[count++].member = mn; + change->args[count++].u.member = mn; } if (count) { change->argc = count; @@ -1233,15 +1387,15 @@ static MODCMD_FUNC(cmd_opall) 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) + struct modeNode *mn = channel->members.list[ii]; + if (mn->modes & MODE_CHANOP) continue; change->args[count].mode = MODE_CHANOP; change->args[count++].u.member = mn; } if (count) { change->argc = count; - modcmd_chanmode_announce(change); + modcmd_chanmode_announce(change); } mod_chanmode_free(change); reply("OSMSG_OPALL_DONE", channel->name); @@ -1259,7 +1413,7 @@ static MODCMD_FUNC(cmd_hopall) if (mn->modes & MODE_HALFOP) continue; change->args[count].mode = MODE_HALFOP; - change->args[count++].member = mn; + change->args[count++].u.member = mn; } if (count) { change->argc = count; @@ -1280,10 +1434,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; @@ -1292,27 +1444,28 @@ static MODCMD_FUNC(cmd_whois) reply("OSMSG_WHOIS_HOST", target->ident, target->hostname); if (IsFakeHost(target)) reply("OSMSG_WHOIS_FAKEHOST", target->fakehost); - reply("OSMSG_WHOIS_IP", inet_ntoa(target->ip)); + reply("OSMSG_WHOIS_IP", irc_ntoa(&target->ip)); if (target->modes) { - bpos = 0; + bpos = 0; #define buffer_cat(str) (herelen = strlen(str), memcpy(buffer+bpos, str, herelen), bpos += herelen) - if (IsInvisible(target)) buffer[bpos++] = 'i'; - if (IsWallOp(target)) buffer[bpos++] = 'w'; - if (IsOper(target)) buffer[bpos++] = 'o'; - if (IsGlobal(target)) buffer[bpos++] = 'g'; - if (IsServNotice(target)) buffer[bpos++] = 's'; - - // 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 (IsInvisible(target)) buffer[bpos++] = 'i'; + if (IsWallOp(target)) buffer[bpos++] = 'w'; + if (IsOper(target)) buffer[bpos++] = 'o'; + if (IsGlobal(target)) buffer[bpos++] = 'g'; + if (IsServNotice(target)) buffer[bpos++] = 's'; + + // 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 (target->handle_info) buffer[bpos++] = 'r'; if (IsHiddenHost(target)) buffer[bpos++] = 'x'; if (IsGagged(target)) buffer_cat(" (gagged)"); - if (IsRegistering(target)) buffer_cat(" (registered account)"); - buffer[bpos] = 0; - if (bpos > 0) + if (IsRegistering(target)) buffer_cat(" (registered account)"); + buffer[bpos] = 0; + if (bpos > 0) reply("OSMSG_WHOIS_MODES", buffer); } reply("OSMSG_WHOIS_INFO", target->info); @@ -1324,9 +1477,9 @@ static MODCMD_FUNC(cmd_whois) intervalString(buffer, now - target->timestamp, user->handle_info); reply("OSMSG_WHOIS_NICK_AGE", buffer); if (target->channels.used <= MAX_CHANNELS_WHOIS) - opserv_ison(user, target, "OSMSG_WHOIS_CHANNELS"); + opserv_ison(user, target, "OSMSG_WHOIS_CHANNELS"); else - reply("OSMSG_WHOIS_HIDECHANS"); + reply("OSMSG_WHOIS_HIDECHANS"); return 1; } @@ -1349,15 +1502,15 @@ 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_HALFOP|MODE_VOICE)) + struct modeNode *mn = channel->members.list[ii]; + if (mn->modes & (MODE_CHANOP|MODE_HALFOP|MODE_VOICE)) continue; change->args[count].mode = MODE_VOICE; change->args[count++].u.member = mn; } if (count) { change->argc = count; - modcmd_chanmode_announce(change); + modcmd_chanmode_announce(change); } mod_chanmode_free(change); reply("OSMSG_CHANNEL_VOICED", channel->name); @@ -1371,15 +1524,15 @@ static MODCMD_FUNC(cmd_devoiceall) 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_VOICE)) + struct modeNode *mn = channel->members.list[ii]; + if (!(mn->modes & MODE_VOICE)) continue; change->args[count].mode = MODE_REMOVE | MODE_VOICE; change->args[count++].u.member = mn; } if (count) { change->argc = count; - modcmd_chanmode_announce(change); + modcmd_chanmode_announce(change); } mod_chanmode_free(change); reply("OSMSG_CHANNEL_DEVOICED", channel->name); @@ -1392,8 +1545,10 @@ static MODCMD_FUNC(cmd_stats_bad) { char buffer[400]; /* Show the bad word list.. */ + /* TODO: convert nonprinting chars like bold to $b etc in a usable way */ for (ii=end=0; iiused; ii++) { here_len = strlen(opserv_bad_words->list[ii]); + /* If the line is full output it & start again */ if ((end + here_len + 2) > sizeof(buffer)) { buffer[end] = 0; reply("OSMSG_BADWORD_LIST", buffer); @@ -1428,6 +1583,11 @@ static MODCMD_FUNC(cmd_stats_glines) { return 1; } +static MODCMD_FUNC(cmd_stats_shuns) { + reply("OSMSG_SHUN_COUNT", shun_count()); + return 1; +} + static void trace_links(struct userNode *bot, struct userNode *user, struct server *server, unsigned int depth) { unsigned int nn, pos; @@ -1553,6 +1713,10 @@ static MODCMD_FUNC(cmd_stats_trusted) { struct trusted_host *th; char length[INTERVALLEN], issued[INTERVALLEN], limit[32]; + reply("OSMSG_TRUSTED_LIST"); + reply("OSMSG_TRUSTED_LIST_BAR"); + reply("OSMSG_TRUSTED_LIST_HEADER"); + reply("OSMSG_TRUSTED_LIST_BAR"); if (argc > 1) { th = dict_find(opserv_trusted_hosts, argv[1], NULL); if (th) { @@ -1561,19 +1725,18 @@ static MODCMD_FUNC(cmd_stats_trusted) { if (th->expires) intervalString(length, th->expires - now, user->handle_info); if (th->limit) - sprintf(limit, "limit %lu", th->limit); + sprintf(limit, "%lu", th->limit); reply("OSMSG_HOST_IS_TRUSTED", th->ipaddr, - (th->limit ? limit : "no limit"), - (th->issued ? issued : "some time"), + (th->limit ? limit : "none"), (th->issuer ? th->issuer : ""), - (th->expires ? length : "never"), - (th->reason ? th->reason : "")); + (th->issued ? issued : "some time"), + (th->expires ? length : "never")); + reply("OSMSG_HOST_IS_TRUSTED_DESC", (th->reason ? th->reason : "")); } else { reply("OSMSG_HOST_NOT_TRUSTED", argv[1]); } } else { - reply("OSMSG_TRUSTED_LIST"); for (it = dict_first(opserv_trusted_hosts); it; it = iter_next(it)) { th = iter_data(it); if (th->issued) @@ -1581,15 +1744,16 @@ static MODCMD_FUNC(cmd_stats_trusted) { if (th->expires) intervalString(length, th->expires - now, user->handle_info); if (th->limit) - sprintf(limit, "limit %lu", th->limit); + sprintf(limit, "%lu", th->limit); reply("OSMSG_HOST_IS_TRUSTED", iter_key(it), - (th->limit ? limit : "no limit"), - (th->issued ? issued : "some time"), + (th->limit ? limit : "none"), (th->issuer ? th->issuer : ""), - (th->expires ? length : "never"), - (th->reason ? th->reason : "")); + (th->issued ? issued : "some time"), + (th->expires ? length : "never")); + reply("OSMSG_HOST_IS_TRUSTED_DESC", (th->reason ? th->reason : "")); } } + reply("OSMSG_TRUSTED_LIST_END"); return 1; } @@ -1635,16 +1799,23 @@ static MODCMD_FUNC(cmd_stats_alerts) { const char *reaction; reply("OSMSG_ALERTS_LIST"); + reply("OSMSG_ALERTS_BAR"); + reply("OSMSG_ALERTS_HEADER"); + reply("OSMSG_ALERTS_BAR"); for (it = dict_first(opserv_user_alerts); it; it = iter_next(it)) { alert = iter_data(it); switch (alert->reaction) { case REACT_NOTICE: reaction = "notice"; break; case REACT_KILL: reaction = "kill"; break; + case REACT_SILENT: reaction = "silent"; break; case REACT_GLINE: reaction = "gline"; break; + case REACT_SHUN: reaction = "shun"; break; default: reaction = ""; break; } - reply("OSMSG_ALERT_IS", iter_key(it), alert->owner, reaction, alert->text_discrim); + reply("OSMSG_ALERT_IS", iter_key(it), reaction, alert->owner); + reply("OSMSG_ALERTS_DESC", alert->text_discrim); } + reply("OSMSG_ALERT_END"); return 1; } @@ -1654,7 +1825,7 @@ static MODCMD_FUNC(cmd_stats_gags) { unsigned int nn; if (!gagList) { - reply("OSMSG_NO_GAGS"); + reply("OSMSG_NO_GAGS"); return 1; } for (nn=0, gag=gagList; gag; nn++, gag=gag->next) ; @@ -1694,6 +1865,7 @@ static MODCMD_FUNC(cmd_stats_timeq) { return 1; } +/* static MODCMD_FUNC(cmd_stats_warn) { dict_iterator_t it; @@ -1703,27 +1875,50 @@ static MODCMD_FUNC(cmd_stats_warn) { reply("OSMSG_WARN_LISTEND"); return 1; } +*/ + +#if defined(WITH_MALLOC_X3) +static MODCMD_FUNC(cmd_stats_memory) { + extern unsigned long alloc_count, alloc_size; + send_message_type(MSG_TYPE_NOXLATE, user, cmd->parent->bot, + "%u allocations totalling %u bytes.", + alloc_count, alloc_size); + return 1; +} +#elif defined(WITH_MALLOC_SLAB) +static MODCMD_FUNC(cmd_stats_memory) { + extern unsigned long slab_alloc_count, slab_count, slab_alloc_size; + extern unsigned long big_alloc_count, big_alloc_size; + send_message_type(MSG_TYPE_NOXLATE, user, cmd->parent->bot, + "%u allocations in %u slabs totalling %u bytes.", + slab_alloc_count, slab_count, slab_alloc_size); +/* send_message_type(MSG_TYPE_NOXLATE, user, cmd->parent->bot, + "%u big allocations totalling %u bytes.", + */ + return 1; +} +#endif static MODCMD_FUNC(cmd_dump) { - char linedup[MAXLEN], *original; + char linedup[MAXLEN], original[MAXLEN]; - original = unsplit_string(argv+1, argc-1, NULL); + unsplit_string(argv+1, argc-1, original); safestrncpy(linedup, original, sizeof(linedup)); /* assume it's only valid IRC if we can parse it */ if (parse_line(linedup, 1)) { - irc_raw(original); - reply("OSMSG_LINE_DUMPED"); + irc_raw(original); + reply("OSMSG_LINE_DUMPED"); } else - reply("OSMSG_RAW_PARSE_ERROR"); + reply("OSMSG_RAW_PARSE_ERROR"); return 1; } static MODCMD_FUNC(cmd_raw) { - char linedup[MAXLEN], *original; + char linedup[MAXLEN], original[MAXLEN]; - original = unsplit_string(argv+1, argc-1, NULL); + unsplit_string(argv+1, argc-1, original); safestrncpy(linedup, original, sizeof(linedup)); /* Try to parse the line before sending it; if it's too wrong, * maybe it will core us instead of our uplink. */ @@ -1738,15 +1933,15 @@ opserv_add_reserve(struct svccmd *cmd, struct userNode *user, const char *nick, { struct userNode *resv = GetUserH(nick); if (resv) { - if (IsService(resv)) { - reply("MSG_SERVICE_IMMUNE", resv->nick); - return NULL; - } - if (resv->handle_info - && resv->handle_info->opserv_level > user->handle_info->opserv_level) { - reply("OSMSG_LEVEL_TOO_LOW"); - return NULL; - } + if (IsService(resv)) { + reply("MSG_SERVICE_IMMUNE", resv->nick); + return NULL; + } + if (resv->handle_info + && resv->handle_info->opserv_level > user->handle_info->opserv_level) { + reply("OSMSG_LEVEL_TOO_LOW"); + return NULL; + } } if ((resv = AddClone(nick, ident, host, desc))) { dict_insert(opserv_reserved_nick_dict, resv->nick, resv); @@ -1760,11 +1955,11 @@ static MODCMD_FUNC(cmd_collide) resv = opserv_add_reserve(cmd, user, argv[1], argv[2], argv[3], unsplit_string(argv+4, argc-4, NULL)); if (resv) { - reply("OSMSG_COLLIDED_NICK", resv->nick); - return 1; + reply("OSMSG_COLLIDED_NICK", resv->nick); + return 1; } else { reply("OSMSG_CLONE_FAILED", argv[1]); - return 0; + return 0; } } @@ -1774,12 +1969,12 @@ static MODCMD_FUNC(cmd_reserve) resv = opserv_add_reserve(cmd, user, argv[1], argv[2], argv[3], unsplit_string(argv+4, argc-4, NULL)); if (resv) { - resv->modes |= FLAGS_PERSISTENT; - reply("OSMSG_RESERVED_NICK", resv->nick); - return 1; + resv->modes |= FLAGS_PERSISTENT; + reply("OSMSG_RESERVED_NICK", resv->nick); + return 1; } else { reply("OSMSG_CLONE_FAILED", argv[1]); - return 0; + return 0; } } @@ -1805,9 +2000,9 @@ free_reserve(char *nick) static MODCMD_FUNC(cmd_unreserve) { if (free_reserve(argv[1])) - reply("OSMSG_NICK_UNRESERVED", argv[1]); + reply("OSMSG_NICK_UNRESERVED", argv[1]); else - reply("OSMSG_NOT_RESERVED", argv[1]); + reply("OSMSG_NOT_RESERVED", argv[1]); return 1; } @@ -1824,6 +2019,7 @@ opserv_new_user_check(struct userNode *user) { struct opserv_hostinfo *ohi; struct gag_entry *gag; + char addr[IRC_NTOP_MAX_SIZE]; /* Check to see if we should ignore them entirely. */ if (IsLocal(user) || IsService(user)) @@ -1835,16 +2031,17 @@ opserv_new_user_check(struct userNode *user) /* Gag them if appropriate. */ for (gag = gagList; gag; gag = gag->next) { - if (user_matches_glob(user, gag->mask, 1)) { + if (user_matches_glob(user, gag->mask, MATCH_USENICK)) { gag_helper_func(user, NULL); break; } } /* Add to host info struct */ - if (!(ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL))) { + irc_ntop(addr, sizeof(addr), &user->ip); + if (!(ohi = dict_find(opserv_hostinfo_dict, addr, NULL))) { ohi = calloc(1, sizeof(*ohi)); - dict_insert(opserv_hostinfo_dict, strdup(inet_ntoa(user->ip)), ohi); + dict_insert(opserv_hostinfo_dict, strdup(addr), ohi); userList_init(&ohi->clients); } userList_append(&ohi->clients, user); @@ -1862,8 +2059,10 @@ opserv_new_user_check(struct userNode *user) } /* Only warn or G-line if there's an untrusted max and their IP is sane. */ - if (opserv_conf.untrusted_max && user->ip.s_addr && (ntohl(user->ip.s_addr) != INADDR_LOOPBACK)) { - struct trusted_host *th = dict_find(opserv_trusted_hosts, inet_ntoa(user->ip), NULL); + if (opserv_conf.untrusted_max + && irc_in_addr_is_valid(user->ip) + && !irc_in_addr_is_loopback(user->ip)) { + struct trusted_host *th = dict_find(opserv_trusted_hosts, addr, NULL); unsigned int limit = th ? th->limit : opserv_conf.untrusted_max; if (!limit) { /* 0 means unlimited hosts */ @@ -1872,9 +2071,9 @@ opserv_new_user_check(struct userNode *user) for (nn=0; nnclients.used; nn++) send_message(ohi->clients.list[nn], opserv, "OSMSG_CLONE_WARNING"); } else if (ohi->clients.used > limit) { - char target[18]; - sprintf(target, "*@%s", inet_ntoa(user->ip)); - gline_add(opserv->nick, target, opserv_conf.clone_gline_duration, "AUTO Excessive connections from a single host.", now, 1); + char target[IRC_NTOP_MAX_SIZE + 3] = { '*', '@', '\0' }; + strcpy(target + 2, addr); + gline_add(opserv->nick, target, opserv_conf.clone_gline_duration, "Excessive connections from a single host.", now, 1, 1); } } @@ -1885,6 +2084,7 @@ static void opserv_user_cleanup(struct userNode *user, UNUSED_ARG(struct userNode *killer), UNUSED_ARG(const char *why)) { struct opserv_hostinfo *ohi; + char addr[IRC_NTOP_MAX_SIZE]; if (IsLocal(user)) { /* Try to remove it from the reserved nick dict without @@ -1893,9 +2093,11 @@ opserv_user_cleanup(struct userNode *user, UNUSED_ARG(struct userNode *killer), dict_remove(opserv_reserved_nick_dict, user->nick); return; } - if ((ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL))) { + irc_ntop(addr, sizeof(addr), &user->ip); + if ((ohi = dict_find(opserv_hostinfo_dict, addr, NULL))) { userList_remove(&ohi->clients, user); - if (ohi->clients.used == 0) dict_remove(opserv_hostinfo_dict, inet_ntoa(user->ip)); + if (ohi->clients.used == 0) + dict_remove(opserv_hostinfo_dict, addr); } } @@ -1903,9 +2105,10 @@ int opserv_bad_channel(const char *name) { unsigned int found; + int present; - dict_find(opserv_exempt_channels, name, &found); - if (found) + dict_find(opserv_exempt_channels, name, &present); + if (present) return 0; if (gline_find(name)) @@ -1944,17 +2147,19 @@ opserv_shutdown_channel(struct chanNode *channel, const char *reason) static void opserv_channel_check(struct chanNode *newchan) { - char *warning; + /*char *warning; */ if (!newchan->join_policer.params) { newchan->join_policer.last_req = now; newchan->join_policer.params = opserv_conf.join_policer_params; } + /* if ((warning = dict_find(opserv_chan_warn, newchan->name, NULL))) { char message[MAXLEN]; snprintf(message, sizeof(message), "Channel activity warning for channel %s: %s", newchan->name, warning); global_message(MESSAGE_RECIPIENT_OPERS, message); } + */ /* Wait until the join check to shut channels down. */ newchan->bad_channel = opserv_bad_channel(newchan->name); @@ -2220,7 +2425,7 @@ static MODCMD_FUNC(cmd_addtrust) { unsigned long interval; char *reason, *tmp; - struct in_addr tmpaddr; + irc_in_addr_t tmpaddr; unsigned int count; if (dict_find(opserv_trusted_hosts, argv[1], NULL)) { @@ -2228,7 +2433,7 @@ static MODCMD_FUNC(cmd_addtrust) return 0; } - if (!inet_aton(argv[1], &tmpaddr)) { + if (!irc_pton(&tmpaddr, NULL, argv[1])) { reply("OSMSG_BAD_IP", argv[1]); return 0; } @@ -2321,92 +2526,92 @@ static MODCMD_FUNC(cmd_clone) char *userinfo; char ident[USERLEN+1]; - if (argc < 5) { - reply("MSG_MISSING_PARAMS", argv[1]); - OPSERV_SYNTAX(); - return 0; - } - if (clone) { - reply("OSMSG_CLONE_EXISTS", argv[2]); - return 0; - } - userinfo = unsplit_string(argv+4, argc-4, NULL); - for (i=0; argv[3][i] && (inick); - return 1; + return 1; } if (!clone) { - reply("MSG_NICK_UNKNOWN", argv[2]); - return 0; + reply("MSG_NICK_UNKNOWN", argv[2]); + return 0; } if (clone->uplink != self || IsService(clone)) { - reply("OSMSG_NOT_A_CLONE", clone->nick); - return 0; + reply("OSMSG_NOT_A_CLONE", clone->nick); + return 0; } if (!irccasecmp(argv[1], "REMOVE")) { - const char *reason; - if (argc > 3) { - reason = unsplit_string(argv+3, argc-3, NULL); - } else { - char *tmp; - tmp = alloca(strlen(clone->nick) + strlen(OSMSG_PART_REASON)); - sprintf(tmp, OSMSG_PART_REASON, clone->nick); - reason = tmp; - } - DelUser(clone, NULL, 1, reason); - reply("OSMSG_CLONE_REMOVED", argv[2]); - return 1; + const char *reason; + if (argc > 3) { + reason = unsplit_string(argv+3, argc-3, NULL); + } else { + char *tmp; + tmp = alloca(strlen(clone->nick) + strlen(OSMSG_PART_REASON)); + sprintf(tmp, OSMSG_PART_REASON, clone->nick); + reason = tmp; + } + DelUser(clone, NULL, 1, reason); + reply("OSMSG_CLONE_REMOVED", argv[2]); + return 1; } if (argc < 4) { - reply("MSG_MISSING_PARAMS", argv[1]); - OPSERV_SYNTAX(); - return 0; + reply("MSG_MISSING_PARAMS", argv[1]); + OPSERV_SYNTAX(); + return 0; } channel = GetChannel(argv[3]); if (!irccasecmp(argv[1], "JOIN")) { - if (!channel - && !(channel = AddChannel(argv[3], now, NULL, NULL, NULL))) { - reply("MSG_CHANNEL_UNKNOWN", argv[3]); - return 0; - } - AddChannelUser(clone, channel); - reply("OSMSG_CLONE_JOINED", clone->nick, channel->name); - return 1; + if (!channel + && !(channel = AddChannel(argv[3], now, NULL, NULL, NULL))) { + reply("MSG_CHANNEL_UNKNOWN", argv[3]); + return 0; + } + AddChannelUser(clone, channel); + reply("OSMSG_CLONE_JOINED", clone->nick, channel->name); + return 1; } if (!irccasecmp(argv[1], "PART")) { - if (!channel) { - reply("MSG_CHANNEL_UNKNOWN", argv[3]); - return 0; - } - if (!GetUserMode(channel, clone)) { - reply("OSMSG_NOT_ON_CHANNEL", clone->nick, channel->name); - return 0; - } - reply("OSMSG_CLONE_PARTED", clone->nick, channel->name); - DelChannelUser(clone, channel, "Leaving.", 0); - return 1; + if (!channel) { + reply("MSG_CHANNEL_UNKNOWN", argv[3]); + return 0; + } + if (!GetUserMode(channel, clone)) { + reply("OSMSG_NOT_ON_CHANNEL", clone->nick, channel->name); + return 0; + } + reply("OSMSG_CLONE_PARTED", clone->nick, channel->name); + DelChannelUser(clone, channel, "Leaving.", 0); + return 1; } if (!irccasecmp(argv[1], "OP")) { struct mod_chanmode change; - if (!channel) { - reply("MSG_CHANNEL_UNKNOWN", argv[3]); - return 0; - } + if (!channel) { + reply("MSG_CHANNEL_UNKNOWN", argv[3]); + return 0; + } mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_CHANOP; @@ -2414,10 +2619,10 @@ static MODCMD_FUNC(cmd_clone) if (!change.args[0].u.member) { reply("OSMSG_NOT_ON_CHANNEL", clone->nick, channel->name); return 0; - } + } modcmd_chanmode_announce(&change); - reply("OSMSG_OPS_GIVEN", channel->name, clone->nick); - return 1; + reply("OSMSG_OPS_GIVEN", channel->name, clone->nick); + return 1; } if (!irccasecmp(argv[1], "HOP")) { struct mod_chanmode change; @@ -2428,8 +2633,8 @@ static MODCMD_FUNC(cmd_clone) mod_chanmode_init(&change); change.argc = 1; change.args[0].mode = MODE_HALFOP; - 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; } @@ -2438,15 +2643,15 @@ static MODCMD_FUNC(cmd_clone) return 1; } if (argc < 5) { - reply("MSG_MISSING_PARAMS", argv[1]); - OPSERV_SYNTAX(); - return 0; + reply("MSG_MISSING_PARAMS", argv[1]); + OPSERV_SYNTAX(); + return 0; } if (!irccasecmp(argv[1], "SAY")) { - char *text = unsplit_string(argv+4, argc-4, NULL); - irc_privmsg(clone, argv[3], text); - reply("OSMSG_CLONE_SAID", clone->nick, argv[3]); - return 1; + char *text = unsplit_string(argv+4, argc-4, NULL); + irc_privmsg(clone, argv[3], text); + reply("OSMSG_CLONE_SAID", clone->nick, argv[3]); + return 1; } reply("OSMSG_UNKNOWN_SUBCOMMAND", argv[1], argv[0]); return 0; @@ -2529,18 +2734,18 @@ int add_reserved(const char *key, void *data, void *extra) struct userNode *reserve; ident = database_get_data(rd->d.object, KEY_IDENT, RECDB_QSTRING); if (!ident) { - log_module(OS_LOG, LOG_ERROR, "Missing ident for reserve of %s", key); - return 0; + log_module(OS_LOG, LOG_ERROR, "Missing ident for reserve of %s", key); + return 0; } hostname = database_get_data(rd->d.object, KEY_HOSTNAME, RECDB_QSTRING); if (!hostname) { - log_module(OS_LOG, LOG_ERROR, "Missing hostname for reserve of %s", key); - return 0; + log_module(OS_LOG, LOG_ERROR, "Missing hostname for reserve of %s", key); + return 0; } desc = database_get_data(rd->d.object, KEY_DESC, RECDB_QSTRING); if (!desc) { - log_module(OS_LOG, LOG_ERROR, "Missing description for reserve of %s", key); - return 0; + log_module(OS_LOG, LOG_ERROR, "Missing description for reserve of %s", key); + return 0; } if ((reserve = AddClone(key, ident, hostname, desc))) { reserve->modes |= FLAGS_PERSISTENT; @@ -2564,20 +2769,16 @@ foreach_matching_user(const char *hostmask, discrim_search_func func, void *extr discrim->max_channels = INT_MAX; discrim->authed = -1; discrim->info_space = -1; + discrim->intra_scmp = 0; + discrim->intra_dcmp = 0; + discrim->use_regex = 0; dupmask = strdup(hostmask); if (split_ircmask(dupmask, &discrim->mask_nick, &discrim->mask_ident, &discrim->mask_host)) { - if (discrim->mask_host && !discrim->mask_host[strspn(discrim->mask_host, "0123456789.?*")]) { - if (!parse_ipmask(discrim->mask_host, &discrim->ip_addr, &discrim->ip_mask)) { - log_module(OS_LOG, LOG_ERROR, "Couldn't parse %s as an IP mask!", discrim->mask_host); - free(discrim); - free(dupmask); - return 0; - } - discrim->mask_host = 0; - } + if (!irc_pton(&discrim->ip_mask, &discrim->ip_mask_bits, discrim->mask_host)) + discrim->ip_mask_bits = 0; matched = opserv_discrim_search(discrim, func, extra); } else { - log_module(OS_LOG, LOG_ERROR, "Couldn't split IRC mask for gag %s!", hostmask); + log_module(OS_LOG, LOG_ERROR, "Couldn't split IRC mask for gag %s!", hostmask); matched = 0; } free(discrim); @@ -2661,15 +2862,15 @@ opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_react char *name_dup; if (dict_find(opserv_user_alerts, name, NULL)) { - send_message(req, opserv, "OSMSG_ALERT_EXISTS", name); - return NULL; + send_message(req, opserv, "OSMSG_ALERT_EXISTS", name); + return NULL; } alert = malloc(sizeof(*alert)); alert->owner = strdup(req->handle_info ? req->handle_info->handle : req->nick); alert->text_discrim = strdup(text_discrim); 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, wordc, wordv, 0); + alert->discrim = opserv_discrim_create(req, opserv, wordc, wordv, 0); if (!alert->discrim) { free(alert->text_discrim); free(discrim_copy); @@ -2682,26 +2883,33 @@ opserv_add_user_alert(struct userNode *req, const char *name, opserv_alert_react alert->discrim->reason = strdup(name); alert->reaction = reaction; dict_insert(opserv_user_alerts, name_dup, alert); - if (alert->discrim->channel) + /* Stick the alert into the appropriate additional alert dict(s). + * For channel alerts, we only use channels and min_channels; + * max_channels would have to be checked on /part, which we do not + * yet do, and which seems of questionable value. + */ + if (alert->discrim->channel || alert->discrim->min_channels) dict_insert(opserv_channel_alerts, name_dup, alert); - else if (alert->discrim->mask_nick) + if (alert->discrim->mask_nick) dict_insert(opserv_nick_based_alerts, name_dup, alert); return alert; } +/* static int add_chan_warn(const char *key, void *data, UNUSED_ARG(void *extra)) { struct record_data *rd = data; char *reason = GET_RECORD_QSTRING(rd); - /* i hope this can't happen */ + * i hope this can't happen * if (!reason) reason = "No Reason"; dict_insert(opserv_chan_warn, strdup(key), strdup(reason)); return 0; } +*/ static int add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra)) @@ -2721,8 +2929,12 @@ add_user_alert(const char *key, void *data, UNUSED_ARG(void *extra)) reaction = REACT_NOTICE; else if (!irccasecmp(react, "kill")) reaction = REACT_KILL; + else if (!irccasecmp(react, "silent")) + reaction = REACT_SILENT; else if (!irccasecmp(react, "gline")) reaction = REACT_GLINE; + else if (!irccasecmp(react, "shun")) + reaction = REACT_SHUN; else { log_module(OS_LOG, LOG_ERROR, "Invalid reaction %s for alert %s.", react, key); return 0; @@ -2819,8 +3031,10 @@ opserv_saxdb_read(struct dict *conf_db) dict_foreach(object, add_gag_helper, NULL); if ((object = database_get_data(conf_db, KEY_ALERTS, RECDB_OBJECT))) dict_foreach(object, add_user_alert, NULL); +/* if ((object = database_get_data(conf_db, KEY_WARN, RECDB_OBJECT))) dict_foreach(object, add_chan_warn, NULL); +*/ return 0; } @@ -2886,6 +3100,7 @@ opserv_saxdb_write(struct saxdb_context *ctx) saxdb_end_record(ctx); } /* channel warnings */ + /* if (dict_size(opserv_chan_warn)) { saxdb_start_record(ctx, KEY_WARN, 0); for (it = dict_first(opserv_chan_warn); it; it = iter_next(it)) { @@ -2893,6 +3108,7 @@ opserv_saxdb_write(struct saxdb_context *ctx) } saxdb_end_record(ctx); } + */ /* alerts */ if (dict_size(opserv_user_alerts)) { saxdb_start_record(ctx, KEY_ALERTS, 1); @@ -2905,7 +3121,9 @@ opserv_saxdb_write(struct saxdb_context *ctx) switch (alert->reaction) { case REACT_NOTICE: reaction = "notice"; break; case REACT_KILL: reaction = "kill"; break; + case REACT_SILENT: reaction = "silent"; break; case REACT_GLINE: reaction = "gline"; break; + case REACT_SHUN: reaction = "shun"; 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)); @@ -2938,29 +3156,29 @@ static MODCMD_FUNC(cmd_query) char *nodename; if (argc < 2) { - reply("OSMSG_OPTION_ROOT"); - conf_enum_root(query_keys_helper, user); - return 1; + reply("OSMSG_OPTION_ROOT"); + conf_enum_root(query_keys_helper, user); + return 1; } nodename = unsplit_string(argv+1, argc-1, NULL); if (!(rd = conf_get_node(nodename))) { - reply("OSMSG_UNKNOWN_OPTION", nodename); - return 0; + reply("OSMSG_UNKNOWN_OPTION", nodename); + return 0; } if (rd->type == RECDB_QSTRING) - reply("OSMSG_OPTION_IS", nodename, rd->d.qstring); + reply("OSMSG_OPTION_IS", nodename, rd->d.qstring); else if (rd->type == RECDB_STRING_LIST) { - reply("OSMSG_OPTION_LIST", nodename); - if (rd->d.slist->used) - for (i=0; id.slist->used; i++) - send_message_type(4, user, cmd->parent->bot, "$b%s$b", rd->d.slist->list[i]); - else - reply("OSMSG_OPTION_LIST_EMPTY"); + reply("OSMSG_OPTION_LIST", nodename); + if (rd->d.slist->used) + for (i=0; id.slist->used; i++) + send_message_type(4, user, cmd->parent->bot, "$b%s$b", rd->d.slist->list[i]); + else + reply("OSMSG_OPTION_LIST_EMPTY"); } else if (rd->type == RECDB_OBJECT) { - reply("OSMSG_OPTION_KEYS", nodename); - dict_foreach(rd->d.object, query_keys_helper, user); + reply("OSMSG_OPTION_KEYS", nodename); + dict_foreach(rd->d.object, query_keys_helper, user); } return 1; @@ -2976,13 +3194,13 @@ static MODCMD_FUNC(cmd_set) invent a syntax for it. -Zoot */ if (!(rd = conf_get_node(argv[1]))) { - reply("OSMSG_SET_NOT_SET", argv[1]); - return 0; + reply("OSMSG_SET_NOT_SET", argv[1]); + return 0; } if (rd->type != RECDB_QSTRING) { - reply("OSMSG_SET_BAD_TYPE", argv[1]); - return 0; + reply("OSMSG_SET_BAD_TYPE", argv[1]); + return 0; } free(rd->d.qstring); @@ -3007,7 +3225,7 @@ static MODCMD_FUNC(cmd_settime) } static discrim_t -opserv_discrim_create(struct userNode *user, 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) { unsigned int i, j; discrim_t discrim; @@ -3020,6 +3238,8 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in discrim->max_channels = INT_MAX; discrim->authed = -1; discrim->info_space = -1; + discrim->intra_dcmp = 0; + discrim->intra_scmp = 0; for (i=0; iintra_dcmp = 1; + else if (!strcasecmp(tmp, "ident")) + discrim->intra_dcmp = 2; + else if (!strcasecmp(tmp, "info")) + discrim->intra_dcmp = 3; + } + } + if (irccasecmp(argv[i], "mask") == 0) { + if (!is_ircmask(argv[++i])) { + send_message(user, bot, "OSMSG_INVALID_IRCMASK", argv[i]); + goto fail; + } + if (!split_ircmask(argv[i], &discrim->mask_nick, &discrim->mask_ident, &discrim->mask_host)) { - send_message(user, opserv, "OSMSG_INVALID_IRCMASK", argv[i]); - goto fail; - } - } else if (irccasecmp(argv[i], "nick") == 0) { - discrim->mask_nick = argv[++i]; - } else if (irccasecmp(argv[i], "ident") == 0) { - discrim->mask_ident = argv[++i]; - } else if (irccasecmp(argv[i], "host") == 0) { - discrim->mask_host = argv[++i]; - } else if (irccasecmp(argv[i], "info") == 0) { - discrim->mask_info = argv[++i]; - } else if (irccasecmp(argv[i], "server") == 0) { - discrim->server = argv[++i]; - } else if (irccasecmp(argv[i], "ip") == 0) { - j = parse_ipmask(argv[++i], &discrim->ip_addr, &discrim->ip_mask); - if (!j) discrim->ip_mask_str = argv[i]; + send_message(user, bot, "OSMSG_INVALID_IRCMASK", argv[i]); + goto fail; + } + } else if (irccasecmp(argv[i], "nick") == 0) { + i++; + if (discrim->intra_dcmp > 0) + discrim->intra_scmp = 1; + else + discrim->mask_nick = argv[i]; + } else if (irccasecmp(argv[i], "ident") == 0) { + i++; + if (discrim->intra_dcmp > 0) + discrim->intra_scmp = 2; + else + discrim->mask_ident = argv[i]; + } else if (irccasecmp(argv[i], "host") == 0) { + discrim->mask_host = argv[++i]; + } else if (irccasecmp(argv[i], "info") == 0) { + i++; + if (discrim->intra_dcmp > 0) + discrim->intra_scmp = 3; + else + discrim->mask_info = argv[i]; + } else if (irccasecmp(argv[i], "server") == 0) { + discrim->server = argv[++i]; + } else if (irccasecmp(argv[i], "ip") == 0) { + j = irc_pton(&discrim->ip_mask, &discrim->ip_mask_bits, argv[++i]); + if (!j) { + send_message(user, opserv, "OSMSG_BAD_IP", argv[i]); + goto fail; + } } else if (irccasecmp(argv[i], "account") == 0) { if (discrim->authed == 0) { - send_message(user, opserv, "OSMSG_ACCOUNTMASK_AUTHED"); + send_message(user, bot, "OSMSG_ACCOUNTMASK_AUTHED"); goto fail; } discrim->accountmask = argv[++i]; @@ -3069,12 +3316,12 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in discrim->authed = 1; } else if (false_string(argv[i])) { if (discrim->accountmask) { - send_message(user, opserv, "OSMSG_ACCOUNTMASK_AUTHED"); + send_message(user, bot, "OSMSG_ACCOUNTMASK_AUTHED"); goto fail; } discrim->authed = 0; } else { - send_message(user, opserv, "MSG_INVALID_BINARY", argv[i]); + send_message(user, bot, "MSG_INVALID_BINARY", argv[i]); goto fail; } } else if (irccasecmp(argv[i], "info_space") == 0) { @@ -3085,13 +3332,23 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in discrim->info_space = 1; } else if (false_string(argv[i])) { discrim->info_space = 0; + } else { + send_message(user, bot, "MSG_INVALID_BINARY", argv[i]); + goto fail; + } + } else if (irccasecmp(argv[i], "regex") == 0) { + i++; + if (true_string(argv[i])) { + discrim->use_regex = 1; + } else if (false_string(argv[i])) { + discrim->use_regex = 0; } else { send_message(user, opserv, "MSG_INVALID_BINARY", argv[i]); goto fail; } } else if (irccasecmp(argv[i], "duration") == 0) { discrim->duration = ParseInterval(argv[++i]); - } else if (irccasecmp(argv[i], "channel") == 0) { + } else if (irccasecmp(argv[i], "channel") == 0) { for (j=0, i++; ; j++) { switch (argv[i][j]) { case '#': @@ -3113,27 +3370,27 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in discrim->chan_req_modes |= MODE_CHANOP; break; case '\0': - send_message(user, opserv, "MSG_NOT_CHANNEL_NAME"); + send_message(user, bot, "MSG_NOT_CHANNEL_NAME"); goto fail; } } find_channel: discrim->chan_no_modes &= ~discrim->chan_req_modes; - if (!(discrim->channel = GetChannel(argv[i]+j))) { + if (!(discrim->channel = GetChannel(argv[i]+j))) { /* secretly "allow_channel" now means "if a channel name is * specified, require that it currently exist" */ if (allow_channel) { - send_message(user, opserv, "MSG_CHANNEL_UNKNOWN", argv[i]); + send_message(user, bot, "MSG_CHANNEL_UNKNOWN", argv[i]); goto fail; } else { discrim->channel = AddChannel(argv[i]+j, now, NULL, NULL, NULL); } - } + } LockChannel(discrim->channel); } else if (irccasecmp(argv[i], "numchannels") == 0) { discrim->min_channels = discrim->max_channels = strtoul(argv[++i], NULL, 10); - } else if (irccasecmp(argv[i], "limit") == 0) { - discrim->limit = strtoul(argv[++i], NULL, 10); + } else if (irccasecmp(argv[i], "limit") == 0) { + discrim->limit = strtoul(argv[++i], NULL, 10); } else if (irccasecmp(argv[i], "reason") == 0) { discrim->reason = strdup(unsplit_string(argv+i+1, argc-i-1, NULL)); i = argc; @@ -3185,33 +3442,108 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in } else if (irccasecmp(argv[i], "clones") == 0) { discrim->min_clones = strtoul(argv[++i], NULL, 0); } else { - send_message(user, opserv, "MSG_INVALID_CRITERIA", argv[i]); + send_message(user, bot, "MSG_INVALID_CRITERIA", argv[i]); goto fail; } } if (discrim->mask_nick && !strcmp(discrim->mask_nick, "*")) { - discrim->mask_nick = 0; + discrim->mask_nick = 0; } if (discrim->mask_ident && !strcmp(discrim->mask_ident, "*")) { discrim->mask_ident = 0; } if (discrim->mask_info && !strcmp(discrim->mask_info, "*")) { - discrim->mask_info = 0; + discrim->mask_info = 0; } if (discrim->mask_host && !discrim->mask_host[strspn(discrim->mask_host, "*.")]) { discrim->mask_host = 0; } + + if(discrim->use_regex) + { + if(discrim->mask_nick) + { + int err = regcomp(&discrim->regex_nick, discrim->mask_nick, REG_EXTENDED|REG_ICASE|REG_NOSUB); + discrim->has_regex_nick = !err; + if(err) + { + char buff[256]; + buff[regerror(err, &discrim->regex_nick, buff, sizeof(buff))] = 0; + + send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_nick, buff, err); + goto regfail; + } + } + + if(discrim->mask_ident) + { + int err = regcomp(&discrim->regex_ident, discrim->mask_ident, REG_EXTENDED|REG_ICASE|REG_NOSUB); + discrim->has_regex_ident = !err; + if(err) + { + char buff[256]; + buff[regerror(err, &discrim->regex_ident, buff, sizeof(buff))] = 0; + + send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_ident, buff, err); + goto regfail; + } + } + + if(discrim->mask_host) + { + int err = regcomp(&discrim->regex_host, discrim->mask_host, REG_EXTENDED|REG_ICASE|REG_NOSUB); + discrim->has_regex_host = !err; + if(err) + { + char buff[256]; + buff[regerror(err, &discrim->regex_host, buff, sizeof(buff))] = 0; + + send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_host, buff, err); + goto regfail; + } + } + + if(discrim->mask_info) + { + int err = regcomp(&discrim->regex_info, discrim->mask_info, REG_EXTENDED|REG_ICASE|REG_NOSUB); + discrim->has_regex_info = !err; + if(err) + { + char buff[256]; + buff[regerror(err, &discrim->regex_info, buff, sizeof(buff))] = 0; + + send_message(user, opserv, "OSMSG_INVALID_REGEX", discrim->mask_info, buff, err); + goto regfail; + } + } + } + return discrim; + fail: free(discrim); return NULL; + + regfail: + if(discrim->has_regex_nick) + regfree(&discrim->regex_nick); + if(discrim->has_regex_ident) + regfree(&discrim->regex_ident); + if(discrim->has_regex_host) + regfree(&discrim->regex_host); + if(discrim->has_regex_info) + regfree(&discrim->regex_info); + + free(discrim); + return NULL; } static int discrim_match(discrim_t discrim, struct userNode *user) { unsigned int access; + char *scmp=NULL, *dcmp=NULL; if ((user->timestamp < discrim->min_ts) || (user->timestamp > discrim->max_ts) @@ -3221,27 +3553,68 @@ discrim_match(discrim_t discrim, struct userNode *user) || (discrim->authed == 1 && !user->handle_info) || (discrim->info_space == 0 && user->info[0] == ' ') || (discrim->info_space == 1 && user->info[0] != ' ') - || (discrim->mask_nick && !match_ircglob(user->nick, discrim->mask_nick)) - || (discrim->mask_ident && !match_ircglob(user->ident, discrim->mask_ident)) - || (discrim->mask_host && !match_ircglob(user->hostname, discrim->mask_host)) - || (discrim->mask_info && !match_ircglob(user->info, discrim->mask_info)) || (discrim->server && !match_ircglob(user->uplink->name, discrim->server)) || (discrim->accountmask && (!user->handle_info || !match_ircglob(user->handle_info->handle, discrim->accountmask))) - || (discrim->ip_mask && !MATCH_IPMASK(user->ip, discrim->ip_addr, discrim->ip_mask))) { + || (discrim->ip_mask_bits && !irc_check_mask(&user->ip, &discrim->ip_mask, discrim->ip_mask_bits)) + ) + return 0; + + if (discrim->channel && !GetUserMode(discrim->channel, user)) return 0; + + if(discrim->use_regex) + { + if((discrim->has_regex_nick && regexec(&discrim->regex_nick, user->nick, 0, 0, 0)) + || (discrim->has_regex_ident && regexec(&discrim->regex_ident, user->ident, 0, 0, 0)) + || (discrim->has_regex_host && regexec(&discrim->regex_host, user->hostname, 0, 0, 0)) + || (discrim->has_regex_info && regexec(&discrim->regex_info, user->info, 0, 0, 0))) { + return 0; + } } - if (discrim->channel && !GetUserMode(discrim->channel, user)) return 0; + else + { + if ((discrim->mask_nick && !match_ircglob(user->nick, discrim->mask_nick)) + || (discrim->mask_ident && !match_ircglob(user->ident, discrim->mask_ident)) + || (discrim->mask_host && !match_ircglob(user->hostname, discrim->mask_host)) + || (discrim->mask_info && !match_ircglob(user->info, discrim->mask_info))) { + return 0; + } + } + + if ((discrim->intra_scmp > 0 && discrim->intra_dcmp > 0)) { + switch(discrim->intra_scmp) { + case 1: scmp=user->nick; break; + case 2: scmp=user->ident; break; + case 3: + scmp=user->info; + if (discrim->info_space == 1) scmp++; + break; + } + switch(discrim->intra_dcmp) { + case 1: dcmp=user->nick; break; + case 2: dcmp=user->ident; break; + case 3: /* When checking INFO, and info_space is enabled + * ignore the first character in a search + * XXX: Should we ignore ALL leading whitespace? + * Also, what about ignoring ~ in ident? + */ + dcmp=user->info; + if (discrim->info_space == 1) dcmp++; + break; + } + if (irccasecmp(scmp,dcmp)) + return 0; + } + access = user->handle_info ? user->handle_info->opserv_level : 0; if ((access < discrim->min_level) || (access > discrim->max_level)) { return 0; } - if (discrim->ip_mask_str) { - if (!match_ircglob(inet_ntoa(user->ip), discrim->ip_mask_str)) return 0; - } if (discrim->min_clones > 1) { - struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, inet_ntoa(user->ip), NULL); - if (!ohi || (ohi->clients.used < discrim->min_clones)) return 0; + struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, irc_ntoa(&user->ip), NULL); + if (!ohi || (ohi->clients.used < discrim->min_clones)) + return 0; } return 1; } @@ -3268,8 +3641,8 @@ opserv_discrim_search(discrim_t discrim, discrim_search_func dsf, void *data) userList_append(&matched, mn->user); } } - } else if (discrim->ip_mask_str && !discrim->ip_mask_str[strcspn(discrim->ip_mask_str, "?*")]) { - struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, discrim->ip_mask_str, NULL); + } else if (discrim->ip_mask_bits == 128) { + struct opserv_hostinfo *ohi = dict_find(opserv_hostinfo_dict, irc_ntoa(&discrim->ip_mask), NULL); if (!ohi) { userList_clean(&matched); return 0; @@ -3302,10 +3675,10 @@ opserv_discrim_search(discrim_t discrim, discrim_search_func dsf, void *data) log_module(OS_LOG, LOG_INFO, " %s!%s@%s", user->nick, user->ident, user->hostname); } if (dsf(user, data)) { - /* If a search function returns true, it ran into a - problem. Stop going through the list. */ - break; - } + /* If a search function returns true, it ran into a + problem. Stop going through the list. */ + break; + } } if (discrim->option_log) { log_module(OS_LOG, LOG_INFO, "End of matching users."); @@ -3320,9 +3693,9 @@ trace_print_func(struct userNode *match, void *extra) { struct discrim_and_source *das = extra; if (match->handle_info) { - send_message_type(4, das->source, opserv, "%s!%s@%s %s", match->nick, match->ident, match->hostname, match->handle_info->handle); + send_message_type(4, das->source, das->destination, "%-15s\002 \002%10s\002@\002%s (%s)", match->nick, match->ident, match->hostname, match->handle_info->handle); } else { - send_message_type(4, das->source, opserv, "%s!%s@%s", match->nick, match->ident, match->hostname); + send_message_type(4, das->source, das->destination, "%-15s\002 \002%10s\002@\002%s", match->nick, match->ident, match->hostname); } return 0; } @@ -3348,7 +3721,19 @@ trace_gline_func(struct userNode *match, void *extra) struct discrim_and_source *das = extra; if (is_oper_victim(das->source, match, das->discrim->match_opers)) { - opserv_block(match, das->source->handle_info->handle, das->discrim->reason, das->discrim->duration); + opserv_block(match, das->source->handle_info->handle, das->discrim->reason, das->discrim->duration, 0); + } + + return 0; +} + +static int +trace_shun_func(struct userNode *match, void *extra) +{ + struct discrim_and_source *das = extra; + + if (is_oper_victim(das->source, match, das->discrim->match_opers)) { + opserv_shun(match, das->source->handle_info->handle, das->discrim->reason, das->discrim->duration); } return 0; @@ -3360,7 +3745,7 @@ trace_kill_func(struct userNode *match, void *extra) struct discrim_and_source *das = extra; if (is_oper_victim(das->source, match, das->discrim->match_opers)) { - char *reason; + char *reason; if (das->discrim->reason) { reason = das->discrim->reason; } else { @@ -3398,10 +3783,10 @@ trace_gag_func(struct userNode *match, void *extra) reason = alloca(strlen(OSMSG_GAG_REQUESTED)+strlen(das->source->nick)+1); sprintf(reason, OSMSG_GAG_REQUESTED, das->source->nick); } - masksize = 5+strlen(match->hostname); - mask = alloca(masksize); + masksize = 5+strlen(match->hostname); + mask = alloca(masksize); snprintf(mask, masksize, "*!*@%s", match->hostname); - if (!is_gagged(mask)) { + if (!is_gagged(mask)) { gag_create(mask, das->source->handle_info->handle, reason, das->discrim->duration ? (now + das->discrim->duration) : 0); } @@ -3414,29 +3799,42 @@ static int trace_domains_func(struct userNode *match, void *extra) { struct discrim_and_source *das = extra; + irc_in_addr_t ip; unsigned long *count; unsigned int depth; char *hostname; + char ipmask[IRC_NTOP_MASK_MAX_SIZE]; - if (!match->hostname[strspn(match->hostname, "0123456789.")]) { - char ipmask[16]; - unsigned long matchip = ntohl(match->ip.s_addr); - /* raw IP address.. use up to first three octets of IP */ - switch (das->discrim->domain_depth) { - default: - snprintf(ipmask, sizeof(ipmask), "%lu.%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255, (matchip>>8)&255); - break; - case 2: - snprintf(ipmask, sizeof(ipmask), "%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255); - break; - case 1: - snprintf(ipmask, sizeof(ipmask), "%lu.*", (matchip>>24)&255); - break; - } + if (irc_pton(&ip, NULL, match->hostname)) { + if (irc_in_addr_is_ipv4(ip)) { + unsigned long matchip = ntohl(ip.in6_32[3]); + /* raw IP address.. use up to first three octets of IP */ + switch (das->discrim->domain_depth) { + default: + snprintf(ipmask, sizeof(ipmask), "%lu.%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255, (matchip>>8)&255); + break; + case 2: + snprintf(ipmask, sizeof(ipmask), "%lu.%lu.*", (matchip>>24)&255, (matchip>>16)&255); + break; + case 1: + snprintf(ipmask, sizeof(ipmask), "%lu.*", (matchip>>24)&255); + break; + } + } else if (irc_in_addr_is_ipv6(ip)) { + switch (das->discrim->domain_depth) { + case 1: depth = 16; goto ipv6_pfx; + case 2: depth = 24; goto ipv6_pfx; + case 3: depth = 32; goto ipv6_pfx; + default: depth = das->discrim->domain_depth; + ipv6_pfx: + irc_ntop_mask(ipmask, sizeof(ipmask), &ip, depth); + } + } else safestrncpy(ipmask, match->hostname, sizeof(ipmask)); + ipmask[sizeof(ipmask) - 1] = '\0'; hostname = ipmask; } else { hostname = match->hostname + strlen(match->hostname); - for (depth=das->discrim->domain_depth; + for (depth=das->discrim->domain_depth; depth && (hostname > match->hostname); depth--) { hostname--; @@ -3458,7 +3856,7 @@ opserv_show_hostinfo(const char *key, void *data, void *extra) unsigned long *count = data; struct discrim_and_source *das = extra; - send_message_type(4, das->source, opserv, "%s %lu", key, *count); + send_message_type(4, das->source, das->destination, "%s %lu", key, *count); return !--das->disp_limit; } @@ -3471,11 +3869,11 @@ static MODCMD_FUNC(cmd_trace) char buf[MAXLEN]; sprintf(buf, "trace %s", argv[1]); - if (!(subcmd = dict_find(cmd->parent->commands, buf, NULL))) { - reply("OSMSG_BAD_ACTION", argv[1]); + if (!(subcmd = dict_find(opserv_service->commands, buf, NULL))) { + reply("OSMSG_BAD_ACTION", argv[1]); return 0; } - if (!svccmd_can_invoke(user, cmd->parent->bot, subcmd, channel, SVCCMD_NOISY)) + if (!svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY)) return 0; if (!irccasecmp(argv[1], "print")) action = trace_print_func; @@ -3485,13 +3883,15 @@ static MODCMD_FUNC(cmd_trace) action = trace_domains_func; else if (!irccasecmp(argv[1], "gline")) action = trace_gline_func; + else if (!irccasecmp(argv[1], "shun")) + action = trace_shun_func; else if (!irccasecmp(argv[1], "kill")) action = trace_kill_func; else if (!irccasecmp(argv[1], "gag")) action = trace_gag_func; else { - reply("OSMSG_BAD_ACTION", argv[1]); - return 0; + reply("OSMSG_BAD_ACTION", argv[1]); + return 0; } if (user->handle_info->opserv_level < subcmd->min_opserv_level) { @@ -3501,16 +3901,24 @@ static MODCMD_FUNC(cmd_trace) das.dict = NULL; das.source = user; - das.discrim = opserv_discrim_create(user, argc-2, argv+2, 1); + das.destination = cmd->parent->bot; + das.discrim = opserv_discrim_create(user, cmd->parent->bot, argc-2, argv+2, 1); if (!das.discrim) return 0; if (action == trace_print_func) - reply("OSMSG_USER_SEARCH_RESULTS"); + { + reply("OSMSG_USER_SEARCH_RESULTS"); + reply("OSMSG_USER_SEARCH_BAR"); + reply("OSMSG_USER_SEARCH_HEADER"); + reply("OSMSG_USER_SEARCH_BAR"); + } else if (action == trace_count_func) - das.discrim->limit = INT_MAX; + das.discrim->limit = INT_MAX; else if ((action == trace_gline_func) && !das.discrim->duration) das.discrim->duration = opserv_conf.block_gline_duration; + else if ((action == trace_shun_func) && !das.discrim->duration) + das.discrim->duration = opserv_conf.block_shun_duration; else if (action == trace_domains_func) { das.dict = dict_new(); dict_set_free_data(das.dict, free); @@ -3524,19 +3932,34 @@ static MODCMD_FUNC(cmd_trace) dict_foreach(das.dict, opserv_show_hostinfo, &das); if (matches) - reply("MSG_MATCH_COUNT", matches); + { + if(action == trace_print_func) + reply("OSMSG_USER_SEARCH_COUNT_BAR", matches); + else + reply("OSMSG_USER_SEARCH_COUNT", matches); + } else - reply("MSG_NO_MATCHES"); + reply("MSG_NO_MATCHES"); if (das.discrim->channel) UnlockChannel(das.discrim->channel); free(das.discrim->reason); + + if(das.discrim->has_regex_nick) + regfree(&das.discrim->regex_nick); + if(das.discrim->has_regex_ident) + regfree(&das.discrim->regex_ident); + if(das.discrim->has_regex_host) + regfree(&das.discrim->regex_host); + if(das.discrim->has_regex_info) + regfree(&das.discrim->regex_info); + free(das.discrim); dict_delete(das.dict); return 1; } -typedef void (*cdiscrim_search_func)(struct chanNode *match, void *data); +typedef void (*cdiscrim_search_func)(struct chanNode *match, void *data, struct userNode *bot); typedef struct channel_discrim { char *name, *topic; @@ -3546,8 +3969,8 @@ typedef struct channel_discrim { unsigned int limit; } *cdiscrim_t; -static cdiscrim_t opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]); -static unsigned int opserv_cdiscrim_search(cdiscrim_t discrim, cdiscrim_search_func dsf, void *data); +static cdiscrim_t opserv_cdiscrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[]); +static unsigned int opserv_cdiscrim_search(cdiscrim_t discrim, cdiscrim_search_func dsf, void *data, struct userNode *bot); static time_t smart_parse_time(const char *str) { @@ -3557,7 +3980,7 @@ smart_parse_time(const char *str) { } static cdiscrim_t -opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]) +opserv_cdiscrim_create(struct userNode *user, struct userNode *bot, unsigned int argc, char *argv[]) { cdiscrim_t discrim; unsigned int i; @@ -3566,18 +3989,18 @@ opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]) discrim->limit = 25; for (i = 0; i < argc; i++) { - /* Assume all criteria require arguments. */ - if (i == (argc - 1)) { - send_message(user, opserv, "MSG_MISSING_PARAMS", argv[i]); - return NULL; - } - - if (!irccasecmp(argv[i], "name")) - discrim->name = argv[++i]; - else if (!irccasecmp(argv[i], "topic")) - discrim->topic = argv[++i]; - else if (!irccasecmp(argv[i], "users")) { - const char *cmp = argv[++i]; + /* Assume all criteria require arguments. */ + if (i == (argc - 1)) { + send_message(user, bot, "MSG_MISSING_PARAMS", argv[i]); + return NULL; + } + + if (!irccasecmp(argv[i], "name")) + discrim->name = argv[++i]; + else if (!irccasecmp(argv[i], "topic")) + discrim->topic = argv[++i]; + else if (!irccasecmp(argv[i], "users")) { + const char *cmp = argv[++i]; if (cmp[0] == '<') { if (cmp[1] == '=') discrim->max_users = strtoul(cmp+2, NULL, 0); @@ -3593,8 +4016,8 @@ opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]) } else { discrim->min_users = strtoul(cmp+2, NULL, 0); } - } else if (!irccasecmp(argv[i], "timestamp")) { - const char *cmp = argv[++i]; + } else if (!irccasecmp(argv[i], "timestamp")) { + const char *cmp = argv[++i]; if (cmp[0] == '<') { if (cmp[1] == '=') discrim->max_ts = smart_parse_time(cmp+2); @@ -3610,18 +4033,18 @@ opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]) } else { discrim->min_ts = smart_parse_time(cmp); } - } else if (!irccasecmp(argv[i], "limit")) { - discrim->limit = strtoul(argv[++i], NULL, 10); - } else { - send_message(user, opserv, "MSG_INVALID_CRITERIA", argv[i]); - goto fail; - } + } else if (!irccasecmp(argv[i], "limit")) { + discrim->limit = strtoul(argv[++i], NULL, 10); + } else { + send_message(user, bot, "MSG_INVALID_CRITERIA", argv[i]); + goto fail; + } } if (discrim->name && !strcmp(discrim->name, "*")) - discrim->name = 0; + discrim->name = 0; if (discrim->topic && !strcmp(discrim->topic, "*")) - discrim->topic = 0; + discrim->topic = 0; return discrim; fail: @@ -3638,40 +4061,40 @@ cdiscrim_match(cdiscrim_t discrim, struct chanNode *chan) (discrim->max_users && chan->members.used > discrim->max_users) || (discrim->min_ts && chan->timestamp < discrim->min_ts) || (discrim->max_ts && chan->timestamp > discrim->max_ts)) { - return 0; + return 0; } return 1; } -static unsigned int opserv_cdiscrim_search(cdiscrim_t discrim, cdiscrim_search_func dsf, void *data) +static unsigned int opserv_cdiscrim_search(cdiscrim_t discrim, cdiscrim_search_func dsf, void *data, struct userNode *bot) { unsigned int count = 0; dict_iterator_t it, next; for (it = dict_first(channels); it && count < discrim->limit ; it = next) { - struct chanNode *chan = iter_data(it); + struct chanNode *chan = iter_data(it); - /* Hold on to the next channel in case we decide to - add actions that destructively modify the channel. */ - next = iter_next(it); - if ((chan->members.used > 0) && cdiscrim_match(discrim, chan)) { - dsf(chan, data); - count++; - } + /* Hold on to the next channel in case we decide to + add actions that destructively modify the channel. */ + next = iter_next(it); + if ((chan->members.used > 0) && cdiscrim_match(discrim, chan)) { + dsf(chan, data, bot); + count++; + } } return count; } -void channel_count(UNUSED_ARG(struct chanNode *channel), UNUSED_ARG(void *data)) +void channel_count(UNUSED_ARG(struct chanNode *channel), UNUSED_ARG(void *data), UNUSED_ARG(struct userNode *bot)) { } -void channel_print(struct chanNode *channel, void *data) +void channel_print(struct chanNode *channel, void *data, struct userNode *bot) { char modes[MAXLEN]; irc_make_chanmode(channel, modes); - send_message(data, opserv, "OSMSG_CSEARCH_CHANNEL_INFO", channel->name, channel->members.used, modes, channel->topic); + send_message(data, bot, "OSMSG_CSEARCH_CHANNEL_INFO", channel->name, channel->members.used, modes, channel->topic); } static MODCMD_FUNC(cmd_csearch) @@ -3683,35 +4106,35 @@ static MODCMD_FUNC(cmd_csearch) char buf[MAXLEN]; if (!irccasecmp(argv[1], "count")) - action = channel_count; + action = channel_count; else if (!irccasecmp(argv[1], "print")) - action = channel_print; + action = channel_print; else { - reply("OSMSG_BAD_ACTION", argv[1]); - return 0; + reply("OSMSG_BAD_ACTION", argv[1]); + return 0; } sprintf(buf, "%s %s", argv[0], argv[0]); - if ((subcmd = dict_find(cmd->parent->commands, buf, NULL)) - && !svccmd_can_invoke(user, cmd->parent->bot, subcmd, channel, SVCCMD_NOISY)) { + if ((subcmd = dict_find(opserv_service->commands, buf, NULL)) + && !svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY)) { return 0; } - discrim = opserv_cdiscrim_create(user, argc - 2, argv + 2); + discrim = opserv_cdiscrim_create(user, cmd->parent->bot, argc - 2, argv + 2); if (!discrim) - return 0; + return 0; if (action == channel_print) - reply("OSMSG_CHANNEL_SEARCH_RESULTS"); + reply("OSMSG_CHANNEL_SEARCH_RESULTS"); else if (action == channel_count) - discrim->limit = INT_MAX; + discrim->limit = INT_MAX; - matches = opserv_cdiscrim_search(discrim, action, user); + matches = opserv_cdiscrim_search(discrim, action, user, cmd->parent->bot); if (matches) - reply("MSG_MATCH_COUNT", matches); + reply("MSG_MATCH_COUNT", matches); else - reply("MSG_NO_MATCHES"); + reply("MSG_NO_MATCHES"); free(discrim); return 1; @@ -3734,9 +4157,27 @@ static MODCMD_FUNC(cmd_gsync) return 1; } +static MODCMD_FUNC(cmd_ssync) +{ + struct server *src; + if (argc > 1) { + src = GetServerH(argv[1]); + if (!src) { + reply("MSG_SERVER_UNKNOWN", argv[1]); + return 0; + } + } else { + src = self->uplink; + } + irc_stats(cmd->parent->bot, src, 'S'); + reply("OSMSG_SSYNC_RUNNING", src->name); + return 1; +} + struct gline_extra { struct userNode *user; struct string_list *glines; + struct userNode *bot; }; static void @@ -3747,7 +4188,7 @@ gtrace_print_func(struct gline *gline, void *extra) strftime(set_text, sizeof(set_text), "%Y-%m-%d", localtime(&gline->issued)); when_text = asctime(localtime(&gline->expires)); when_text[strlen(when_text)-1] = 0; /* strip lame \n */ - send_message(xtra->user, opserv, "OSMSG_GTRACE_FORMAT", gline->target, set_text, gline->issuer, when_text, gline->reason); + send_message(xtra->user, xtra->bot, "OSMSG_GTRACE_FORMAT", gline->target, set_text, gline->issuer, when_text, gline->reason); } static void @@ -3782,8 +4223,8 @@ static MODCMD_FUNC(cmd_gtrace) return 0; } sprintf(buf, "%s %s", argv[0], argv[0]); - if ((subcmd = dict_find(cmd->parent->commands, buf, NULL)) - && !svccmd_can_invoke(user, cmd->parent->bot, subcmd, channel, SVCCMD_NOISY)) { + if ((subcmd = dict_find(opserv_service->commands, buf, NULL)) + && !svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY)) { return 0; } @@ -3798,6 +4239,7 @@ static MODCMD_FUNC(cmd_gtrace) extra.user = user; extra.glines = alloc_string_list(4); + extra.bot = cmd->parent->bot; matches = gline_discrim_search(discrim, action, &extra); if (action == gtrace_ungline_func) @@ -3814,6 +4256,88 @@ static MODCMD_FUNC(cmd_gtrace) return 1; } +struct shun_extra { + struct userNode *user; + struct string_list *shuns; + struct userNode *bot; +}; + +static void +strace_print_func(struct shun *shun, void *extra) +{ + struct shun_extra *xtra = extra; + char *when_text, set_text[20]; + strftime(set_text, sizeof(set_text), "%Y-%m-%d", localtime(&shun->issued)); + when_text = asctime(localtime(&shun->expires)); + when_text[strlen(when_text)-1] = 0; /* strip lame \n */ + send_message(xtra->user, xtra->bot, "OSMSG_STRACE_FORMAT", shun->target, set_text, shun->issuer, when_text, shun->reason); +} + +static void +strace_count_func(UNUSED_ARG(struct shun *shun), UNUSED_ARG(void *extra)) +{ +} + +static void +strace_unshun_func(struct shun *shun, void *extra) +{ + struct shun_extra *xtra = extra; + string_list_append(xtra->shuns, strdup(shun->target)); +} + +static MODCMD_FUNC(cmd_strace) +{ + struct shun_discrim *discrim; + shun_search_func action; + unsigned int matches, nn; + struct shun_extra extra; + struct svccmd *subcmd; + char buf[MAXLEN]; + + if (!irccasecmp(argv[1], "print")) + action = strace_print_func; + else if (!irccasecmp(argv[1], "count")) + action = strace_count_func; + else if (!irccasecmp(argv[1], "unshun")) + action = strace_unshun_func; + else { + reply("OSMSG_BAD_ACTION", argv[1]); + return 0; + } + sprintf(buf, "%s %s", argv[0], argv[0]); + if ((subcmd = dict_find(opserv_service->commands, buf, NULL)) + && !svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY)) { + return 0; + } + + discrim = shun_discrim_create(user, cmd->parent->bot, argc-2, argv+2); + if (!discrim) + return 0; + + if (action == strace_print_func) + reply("OSMSG_SHUN_SEARCH_RESULTS"); + else if (action == strace_count_func) + discrim->limit = INT_MAX; + + extra.user = user; + extra.shuns = alloc_string_list(4); + extra.bot = cmd->parent->bot; + matches = shun_discrim_search(discrim, action, &extra); + + if (action == strace_unshun_func) + for (nn=0; nnused; nn++) + shun_remove(extra.shuns->list[nn], 1); + free_string_list(extra.shuns); + + if (matches) + reply("MSG_MATCH_COUNT", matches); + else + reply("MSG_NO_MATCHES"); + free(discrim->alt_target_mask); + free(discrim); + return 1; +} + static int alert_check_user(const char *key, void *data, void *extra) { @@ -3839,8 +4363,14 @@ alert_check_user(const char *key, void *data, void *extra) case REACT_KILL: DelUser(user, opserv, 1, alert->discrim->reason); return 1; + case REACT_SILENT: + opserv_block(user, alert->owner, alert->discrim->reason, alert->discrim->duration, 1); + return 1; case REACT_GLINE: - opserv_block(user, alert->owner, alert->discrim->reason, alert->discrim->duration); + opserv_block(user, alert->owner, alert->discrim->reason, alert->discrim->duration, 0); + return 1; + case REACT_SHUN: + opserv_shun(user, alert->owner, alert->discrim->reason, alert->discrim->duration); return 1; default: log_module(OS_LOG, LOG_ERROR, "Invalid reaction type %d for alert %s.", alert->reaction, key); @@ -3860,7 +4390,7 @@ opserv_alert_check_nick(struct userNode *user, UNUSED_ARG(const char *old_nick)) /* Gag them if appropriate (and only if). */ user->modes &= ~FLAGS_GAGGED; for (gag = gagList; gag; gag = gag->next) { - if (user_matches_glob(user, gag->mask, 1)) { + if (user_matches_glob(user, gag->mask, MATCH_USENICK)) { gag_helper_func(user, NULL); break; } @@ -3885,7 +4415,7 @@ opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_han else return; - if (user->ip.s_addr) + if (irc_in_addr_is_valid(user->ip)) send_channel_notice(opserv_conf.staff_auth_channel, opserv, IDENT_FORMAT" authed to %s account %s", IDENT_DATA(user), type, user->handle_info->handle); else send_channel_notice(opserv_conf.staff_auth_channel, opserv, "%s [%s@%s] authed to %s account %s", user->nick, user->ident, user->hostname, type, user->handle_info->handle); @@ -3907,9 +4437,9 @@ static MODCMD_FUNC(cmd_log) matches = log_entry_search(discrim, log_report_entry, &report); if (matches) - reply("MSG_MATCH_COUNT", matches); + reply("MSG_MATCH_COUNT", matches); else - reply("MSG_NO_MATCHES"); + reply("MSG_NO_MATCHES"); free(discrim); return 1; @@ -3934,26 +4464,26 @@ static MODCMD_FUNC(cmd_gag) reason = unsplit_string(argv + 3, argc - 3, NULL); if (!is_ircmask(argv[1])) { - reply("OSMSG_INVALID_IRCMASK", argv[1]); + reply("OSMSG_INVALID_IRCMASK", argv[1]); return 0; } for (gag = gagList; gag; gag = gag->next) - if (match_ircglobs(gag->mask, argv[1])) + if (match_ircglobs(gag->mask, argv[1])) break; if (gag) { - reply("OSMSG_REDUNDANT_GAG", argv[1]); - return 0; + reply("OSMSG_REDUNDANT_GAG", argv[1]); + return 0; } duration = ParseInterval(argv[2]); gagged = gag_create(argv[1], user->handle_info->handle, reason, (duration?now+duration:0)); if (gagged) - reply("OSMSG_GAG_APPLIED", argv[1], gagged); + reply("OSMSG_GAG_APPLIED", argv[1], gagged); else - reply("OSMSG_GAG_ADDED", argv[1]); + reply("OSMSG_GAG_ADDED", argv[1]); return 1; } @@ -3970,21 +4500,21 @@ static MODCMD_FUNC(cmd_ungag) unsigned int ungagged; for (gag = gagList; gag; gag = gag->next) - if (!strcmp(gag->mask, argv[1])) + if (!strcmp(gag->mask, argv[1])) break; if (!gag) { - reply("OSMSG_GAG_NOT_FOUND", argv[1]); - return 0; + reply("OSMSG_GAG_NOT_FOUND", argv[1]); + return 0; } timeq_del(gag->expires, gag_expire, gag, 0); ungagged = gag_free(gag); if (ungagged) - reply("OSMSG_UNGAG_APPLIED", argv[1], ungagged); + reply("OSMSG_UNGAG_APPLIED", argv[1], ungagged); else - reply("OSMSG_UNGAG_ADDED", argv[1]); + reply("OSMSG_UNGAG_ADDED", argv[1]); return 1; } @@ -3997,21 +4527,25 @@ static MODCMD_FUNC(cmd_addalert) name = argv[1]; sprintf(buf, "addalert %s", argv[2]); - if (!(subcmd = dict_find(cmd->parent->commands, buf, NULL))) { - reply("OSMSG_UNKNOWN_REACTION", argv[2]); - return 0; + if (!(subcmd = dict_find(opserv_service->commands, buf, NULL))) { + reply("OSMSG_UNKNOWN_REACTION", argv[2]); + return 0; } if (!irccasecmp(argv[2], "notice")) reaction = REACT_NOTICE; else if (!irccasecmp(argv[2], "kill")) reaction = REACT_KILL; + else if (!irccasecmp(argv[2], "silent")) + reaction = REACT_SILENT; else if (!irccasecmp(argv[2], "gline")) reaction = REACT_GLINE; + else if (!irccasecmp(argv[2], "shun")) + reaction = REACT_SHUN; else { - reply("OSMSG_UNKNOWN_REACTION", argv[2]); - return 0; + reply("OSMSG_UNKNOWN_REACTION", argv[2]); + return 0; } - if (!svccmd_can_invoke(user, cmd->parent->bot, subcmd, channel, SVCCMD_NOISY) + if (!svccmd_can_invoke(user, opserv_service->bot, subcmd, channel, SVCCMD_NOISY) || !opserv_add_user_alert(user, name, reaction, unsplit_string(argv + 3, argc - 3, NULL))) return 0; reply("OSMSG_ADDED_ALERT", name); @@ -4024,10 +4558,10 @@ static MODCMD_FUNC(cmd_delalert) for (i=1; itype != RECDB_OBJECT) { - log_module(OS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", OPSERV_CONF_NAME); - return; + log_module(OS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", OPSERV_CONF_NAME); + return; } conf_node = rd->d.object; str = database_get_data(conf_node, KEY_DEBUG_CHANNEL, RECDB_QSTRING); @@ -4052,20 +4586,20 @@ 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, 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; + opserv_conf.debug_channel = NULL; } str = database_get_data(conf_node, KEY_ALERT_CHANNEL, RECDB_QSTRING); if (opserv && str) { 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, 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; + opserv_conf.alert_channel = NULL; } str = database_get_data(conf_node, KEY_STAFF_AUTH_CHANNEL, RECDB_QSTRING); if (opserv && str) { @@ -4077,6 +4611,10 @@ opserv_conf_read(void) } else { opserv_conf.staff_auth_channel = NULL; } + + str = database_get_data(conf_node, KEY_ADMIN_LEVEL, RECDB_QSTRING); + opserv_conf.admin_level = str ? strtoul(str, NULL, 0): 800; + str = database_get_data(conf_node, KEY_UNTRUSTED_MAX, RECDB_QSTRING); opserv_conf.untrusted_max = str ? strtoul(str, NULL, 0) : 5; str = database_get_data(conf_node, KEY_PURGE_LOCK_DELAY, RECDB_QSTRING); @@ -4088,17 +4626,21 @@ opserv_conf_read(void) str = database_get_data(conf_node, KEY_NICK, RECDB_QSTRING); if (opserv && str) NickChange(opserv, str, 0); + str = database_get_data(conf_node, KEY_CLONE_GLINE_DURATION, RECDB_QSTRING); opserv_conf.clone_gline_duration = str ? ParseInterval(str) : 3600; str = database_get_data(conf_node, KEY_BLOCK_GLINE_DURATION, RECDB_QSTRING); opserv_conf.block_gline_duration = str ? ParseInterval(str) : 3600; + str = database_get_data(conf_node, KEY_BLOCK_SHUN_DURATION, RECDB_QSTRING); + opserv_conf.block_shun_duration = str ? ParseInterval(str) : 3600; + if (!opserv_conf.join_policer_params) opserv_conf.join_policer_params = policer_params_new(); policer_params_set(opserv_conf.join_policer_params, "size", "20"); policer_params_set(opserv_conf.join_policer_params, "drain-rate", "1"); if ((child = database_get_data(conf_node, KEY_JOIN_POLICER, RECDB_OBJECT))) - dict_foreach(child, set_policer_param, opserv_conf.join_policer_params); + dict_foreach(child, set_policer_param, opserv_conf.join_policer_params); for (it = dict_first(channels); it; it = iter_next(it)) { struct chanNode *cNode = iter_data(it); @@ -4112,7 +4654,14 @@ opserv_conf_read(void) policer_params_set(pp, "size", "200"); policer_params_set(pp, "drain-rate", "3"); if ((child = database_get_data(conf_node, KEY_NEW_USER_POLICER, RECDB_OBJECT))) - dict_foreach(child, set_policer_param, pp); + dict_foreach(child, set_policer_param, pp); +} + +/* lame way to export opserv_conf value to nickserv.c ... */ +unsigned int +opserv_conf_admin_level() +{ + return(opserv_conf.admin_level); } static void @@ -4122,10 +4671,13 @@ opserv_db_init(void) { opserv_trusted_hosts = dict_new(); dict_set_free_data(opserv_trusted_hosts, free_trusted_host); /* set up opserv_chan_warn dict */ + +/* alert trace notice channel #x replaces warnings dict_delete(opserv_chan_warn); opserv_chan_warn = dict_new(); dict_set_free_keys(opserv_chan_warn, free); dict_set_free_data(opserv_chan_warn, free); +*/ /* set up opserv_user_alerts */ dict_delete(opserv_channel_alerts); opserv_channel_alerts = dict_new(); @@ -4149,7 +4701,7 @@ opserv_db_cleanup(void) { unsigned int nn; - dict_delete(opserv_chan_warn); +/* dict_delete(opserv_chan_warn); */ dict_delete(opserv_reserved_nick_dict); free_string_list(opserv_bad_words); dict_delete(opserv_exempt_channels); @@ -4182,7 +4734,9 @@ 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 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 KILL", NULL, 900, 0, 0); opserv_define_func("ADDBAD", cmd_addbad, 800, 0, 2); opserv_define_func("ADDEXEMPT", cmd_addexempt, 800, 0, 2); @@ -4215,6 +4769,12 @@ init_opserv(const char *nick) opserv_define_func("GTRACE", cmd_gtrace, 100, 0, 3); opserv_define_func("GTRACE COUNT", NULL, 0, 0, 0); opserv_define_func("GTRACE PRINT", NULL, 0, 0, 0); + opserv_define_func("SBLOCK", cmd_sblock, 100, 0, 2); + opserv_define_func("SHUN", cmd_shun, 600, 0, 4); + opserv_define_func("SSYNC", cmd_ssync, 600, 0, 0); + opserv_define_func("STRACE", cmd_strace, 100, 0, 3); + opserv_define_func("STRACE COUNT", NULL, 0, 0, 0); + opserv_define_func("STRACE PRINT", NULL, 0, 0, 0); opserv_define_func("INVITE", cmd_invite, 100, 2, 0); opserv_define_func("INVITEME", cmd_inviteme, 100, 0, 0); opserv_define_func("JOIN", cmd_join, 601, 0, 2); @@ -4235,6 +4795,7 @@ init_opserv(const char *nick) opserv_define_func("RAW", cmd_raw, 999, 0, 2); opserv_define_func("RECONNECT", cmd_reconnect, 900, 0, 0); opserv_define_func("REFRESHG", cmd_refreshg, 600, 0, 0); + opserv_define_func("REFRESHS", cmd_refreshs, 600, 0, 0); opserv_define_func("REHASH", cmd_rehash, 900, 0, 0); opserv_define_func("REOPEN", cmd_reopen, 900, 0, 0); opserv_define_func("RESERVE", cmd_reserve, 800, 0, 5); @@ -4245,6 +4806,7 @@ init_opserv(const char *nick) opserv_define_func("STATS BAD", cmd_stats_bad, 0, 0, 0); opserv_define_func("STATS GAGS", cmd_stats_gags, 0, 0, 0); opserv_define_func("STATS GLINES", cmd_stats_glines, 0, 0, 0); + opserv_define_func("STATS SHUNS", cmd_stats_shuns, 0, 0, 0); opserv_define_func("STATS LINKS", cmd_stats_links, 0, 0, 0); opserv_define_func("STATS MAX", cmd_stats_max, 0, 0, 0); opserv_define_func("STATS NETWORK", cmd_stats_network, 0, 0, 0); @@ -4254,23 +4816,29 @@ init_opserv(const char *nick) opserv_define_func("STATS TRUSTED", cmd_stats_trusted, 0, 0, 0); opserv_define_func("STATS UPLINK", cmd_stats_uplink, 0, 0, 0); opserv_define_func("STATS UPTIME", cmd_stats_uptime, 0, 0, 0); - opserv_define_func("STATS WARN", cmd_stats_warn, 0, 0, 0); +/* opserv_define_func("STATS WARN", cmd_stats_warn, 0, 0, 0); */ +#if defined(WITH_MALLOC_X3) || defined(WITH_MALLOC_SLAB) + opserv_define_func("STATS MEMORY", cmd_stats_memory, 0, 0, 0); +#endif opserv_define_func("TRACE", cmd_trace, 100, 0, 3); opserv_define_func("TRACE PRINT", NULL, 0, 0, 0); opserv_define_func("TRACE COUNT", NULL, 0, 0, 0); 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 GAG", NULL, 600, 0, 0); opserv_define_func("TRACE KILL", NULL, 600, 0, 0); opserv_define_func("UNBAN", cmd_unban, 100, 2, 2); opserv_define_func("UNGAG", cmd_ungag, 600, 0, 2); opserv_define_func("UNGLINE", cmd_ungline, 600, 0, 2); modcmd_register(opserv_module, "GTRACE UNGLINE", NULL, 0, 0, "template", "ungline", NULL); + opserv_define_func("UNSHUN", cmd_unshun, 600, 0, 2); + modcmd_register(opserv_module, "GTRACE UNSHUN", NULL, 0, 0, "template", "unshun", NULL); opserv_define_func("UNJUPE", cmd_unjupe, 900, 0, 2); opserv_define_func("UNRESERVE", cmd_unreserve, 800, 0, 2); - opserv_define_func("UNWARN", cmd_unwarn, 800, 0, 0); +/* opserv_define_func("UNWARN", cmd_unwarn, 800, 0, 0); */ opserv_define_func("VOICEALL", cmd_voiceall, 300, 2, 0); - opserv_define_func("WARN", cmd_warn, 800, 0, 2); +/* opserv_define_func("WARN", cmd_warn, 800, 0, 2); */ opserv_define_func("WHOIS", cmd_whois, 0, 0, 2); opserv_reserved_nick_dict = dict_new(); @@ -4281,7 +4849,7 @@ init_opserv(const char *nick) reg_new_user_func(opserv_new_user_check); reg_nick_change_func(opserv_alert_check_nick); reg_del_user_func(opserv_user_cleanup); - reg_new_channel_func(opserv_channel_check); + reg_new_channel_func(opserv_channel_check); reg_del_channel_func(opserv_channel_delete); reg_join_func(opserv_join_check); reg_auth_func(opserv_staff_alert); @@ -4289,7 +4857,10 @@ init_opserv(const char *nick) opserv_db_init(); saxdb_register("OpServ", opserv_saxdb_read, opserv_saxdb_write); if (nick) - service_register(opserv)->trigger = '?'; + { + opserv_service = service_register(opserv); + opserv_service->trigger = '?'; + } reg_exit_func(opserv_db_cleanup); message_register_table(msgtab);