X-Git-Url: http://git.pk910.de/?p=srvx.git;a=blobdiff_plain;f=src%2Fopserv.c;h=d358d57637b4c59f10a51e819e99ee32115d2e6c;hp=3eb44033e7a515ac5f6068b92bc8de16ad86aa76;hb=52ad451848654edc3f544e7e52eb773b156da9ff;hpb=da8cd3de6f2144016e9eeba741a138c6ac2663a7 diff --git a/src/opserv.c b/src/opserv.c index 3eb4403..d358d57 100644 --- a/src/opserv.c +++ b/src/opserv.c @@ -22,6 +22,7 @@ #include "gline.h" #include "global.h" #include "nickserv.h" +#include "chanserv.h" #include "modcmd.h" #include "opserv.h" #include "timeq.h" @@ -72,10 +73,16 @@ #define KEY_EXPIRES "expires" #define KEY_STAFF_AUTH_CHANNEL "staff_auth_channel" #define KEY_STAFF_AUTH_CHANNEL_MODES "staff_auth_channel_modes" +#define KEY_STAFF_AUTH_FORCE_OPS "staff_auth_force_opers" #define KEY_CLONE_GLINE_DURATION "clone_gline_duration" #define KEY_BLOCK_GLINE_DURATION "block_gline_duration" #define KEY_ISSUER "issuer" #define KEY_ISSUED "issued" +#define KEY_DEVNULL_CLASSES "classes" +#define KEY_DEVNULL_NAME "class" +#define KEY_DEVNULL_MODE "modes" +#define KEY_DEVNULL_MAXCHAN "chanlimit" +#define KEY_DEVNULL_MAXSENDQ "sendq" #define IDENT_FORMAT "%s [%s@%s/%s]" #define IDENT_DATA(user) user->nick, user->ident, user->hostname, irc_ntoa(&user->ip) @@ -116,17 +123,19 @@ static const struct message_entry msgtab[] = { { "OSMSG_OP_DONE", "Opped the requested lusers." }, { "OSMSG_OPALL_DONE", "Opped everyone on $b%s$b." }, { "OSMSG_WHOIS_IDENT", "%s (%s@%s) from %d.%d.%d.%d" }, - { "OSMSG_WHOIS_NICK", "Nick : %s" }, - { "OSMSG_WHOIS_HOST", "Host : %s@%s" }, - { "OSMSG_WHOIS_FAKEHOST", "Fakehost: %s" }, - { "OSMSG_WHOIS_IP", "Real IP : %s" }, - { "OSMSG_WHOIS_MODES", "Modes : +%s " }, - { "OSMSG_WHOIS_INFO", "Info : %s" }, - { "OSMSG_WHOIS_NUMERIC", "Numnick : %s" }, - { "OSMSG_WHOIS_SERVER", "Server : %s" }, - { "OSMSG_WHOIS_NICK_AGE", "Nick Age: %s" }, - { "OSMSG_WHOIS_ACCOUNT", "Account : %s" }, - { "OSMSG_WHOIS_CHANNELS", "Channels: %s" }, + { "OSMSG_WHOIS_NICK", "Nick : %s" }, + { "OSMSG_WHOIS_HOST", "Host : %s@%s" }, + { "OSMSG_WHOIS_FAKEHOST", "Fakehost : %s" }, + { "OSMSG_WHOIS_FAKEIDENT", "Fakeident: %s" }, + { "OSMSG_WHOIS_FAKEIDENTHOST", "Fakehost : %s@%s" }, + { "OSMSG_WHOIS_IP", "Real IP : %s" }, + { "OSMSG_WHOIS_MODES", "Modes : +%s " }, + { "OSMSG_WHOIS_INFO", "Info : %s" }, + { "OSMSG_WHOIS_NUMERIC", "Numnick : %s" }, + { "OSMSG_WHOIS_SERVER", "Server : %s" }, + { "OSMSG_WHOIS_NICK_AGE", "Nick Age : %s" }, + { "OSMSG_WHOIS_ACCOUNT", "Account : %s" }, + { "OSMSG_WHOIS_CHANNELS", "Channels : %s" }, { "OSMSG_WHOIS_HIDECHANS", "Channel list omitted for your sanity." }, { "OSMSG_UNBAN_DONE", "Ban(s) removed from channel %s." }, { "OSMSG_CHANNEL_VOICED", "All users on %s voiced." }, @@ -199,7 +208,9 @@ static const struct message_entry msgtab[] = { { "OSMSG_GLINE_SEARCH_RESULTS", "The following glines were found:" }, { "OSMSG_LOG_SEARCH_RESULTS", "The following log entries were found:" }, { "OSMSG_GSYNC_RUNNING", "Synchronizing glines from %s." }, - { "OSMSG_GTRACE_FORMAT", "%s (issued %s by %s, lastmod %s, expires %s): %s" }, + { "OSMSG_GTRACE_FORMAT", "%1$s (issued %2$s ago by %3$s, lastmod %4$s ago, expires %5$s, lifetime %7$s): %6$s" }, + { "OSMSG_GTRACE_FOREVER", "%1$s (issued %2$s ago by %3$s, lastmod %4$s ago, never expires, lifetime %7$s): %6$s" }, + { "OSMSG_GTRACE_EXPIRED", "%1$s (issued %2$s ago by %3$s, lastmod %4$s ago, expired %5$s ago, lifetime %7$s): %6$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." }, @@ -252,6 +263,44 @@ static const struct message_entry msgtab[] = { { "OSMSG_CHANINFO_USER_COUNT", "Users (%d):" }, { "OSMSG_CSEARCH_CHANNEL_INFO", "%s [%d users] %s %s" }, { "OSMSG_TRACE_MAX_CHANNELS", "You may not use the 'channel' criterion more than %d times." }, + { "OSMSG_FORCEKICK_LOCAL", "You cannot kick $b%s$b forcefully." }, + { "OSMSG_SVSNONICK", "$b%s$b is not a valid nick." }, + { "OSMSG_SVSNICKUSED", "$b%s$b is an already used nickname." }, + { "OSMSG_SVSNICK", "You have renamed $b%s$b to $b%s$b." }, + { "OSMSG_SVSJOIN", "$b%s$b joined $b%s$b." }, + { "OSMSG_SVSMODE", "You have set mode $b%s$b for $b%s$b." }, + { "OSMSG_SIMUL", "You have simuled $b%s$b: %s" }, + { "OSMSG_DEVNULL_USER" , "[%s] %s %s" }, + { "OSMSG_DEVNULL_MATCH" , "%d Users found." }, + { "OSMSG_DEVNULL_CLASS" , "%s is not a valid DevNull class." }, + { "OSMSG_DEVNULL_ADDED", "Added %s to DevNull list (class: %s)" }, + { "OSMSG_DEVNULL_DELETED", "Deleted %s from DevNull list (class: %s)" }, + { "OSMSG_DEVNULL_NOTADDED", "User %s is not listed on DevNull list." }, + { "OSMSG_DEVNULL_ACTION", "Unrecognized trace action $b%s$b" }, + { "OSMSG_DEVNULL_FOUND", "DevNull Class %s is already existing." }, + { "OSMSG_DEVNULL_NOTFOUND", "can't find DevNull class %s." }, + { "OSMSG_DEVNULL_ADDED", "DevNull Class %s added." }, + { "OSMSG_DEVNULL_REMOVED", "DevNull Class %s removed." }, + { "OSMSG_DEVNULL_SET", "Settings for DevNull Class %s" }, + { "OSMSG_DEVNULL_SET_A", "ChanLimit: %s" }, + { "OSMSG_DEVNULL_SET_A_i", "ChanLimit: %i" }, + { "OSMSG_DEVNULL_SET_B", "UnlimitTarget: %s" }, + { "OSMSG_DEVNULL_SET_C", "Flood: %s" }, + { "OSMSG_DEVNULL_SET_E", "ChanHide: %s" }, + { "OSMSG_DEVNULL_SET_F", "IdleHide: %s" }, + { "OSMSG_DEVNULL_SET_G", "ChServMode: %s" }, + { "OSMSG_DEVNULL_SET_H", "XtraOpMode: %s" }, + { "OSMSG_DEVNULL_SET_I", "NetServMode: %s" }, + { "OSMSG_DEVNULL_SET_J", "SeeIdle: %s" }, + { "OSMSG_DEVNULL_SET_K", "ForceIdleHide: %s" }, + { "OSMSG_DEVNULL_SET_L", "OverrideCC: %s" }, + { "OSMSG_DEVNULL_SET_M", "OverrideNoAmsg: %s" }, + { "OSMSG_DEVNULL_SET_N", "MaxSendQ: %s" }, + { "OSMSG_DEVNULL_SET_N_i", "MaxSendQ: %i" }, + { "OSMSG_DEVNULL_SET_OPME", "OpMe: %s" }, + { "OSMSG_DEVNULL_SET_DONE", "Done." }, + { "OSMSG_DEVNULL_RENAMED", "Devnull class %s renamed to %s" }, + { "OSMSG_DEVNULL_SET_INVALID", "Invalid Option for setting %s" }, { NULL, NULL } }; @@ -266,6 +315,7 @@ 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 */ static dict_t opserv_trusted_hosts; /* data is struct trusted_host* */ +static dict_t opserv_devnull_classes; /* data is struct devnull_class* */ static dict_t opserv_hostinfo_dict; /* data is struct opserv_hostinfo* */ static dict_t opserv_user_alerts; /* data is struct opserv_user_alert* */ static dict_t opserv_nick_based_alerts; /* data is struct opserv_user_alert* */ @@ -274,12 +324,15 @@ static dict_t opserv_account_alerts; /* data is struct opserv_user_alert* */ static struct module *opserv_module; static struct log_type *OS_LOG; static unsigned int new_user_flood; +const char *devnull_modes = DEVNULL_MODES; static char *level_strings[1001]; +static char devnull_inverse_modes[256]; static struct { struct chanNode *debug_channel; struct chanNode *alert_channel; struct chanNode *staff_auth_channel; + int staff_auth_force; struct policer_params *join_policer_params; struct policer new_user_policer; unsigned long untrusted_max; @@ -295,15 +348,15 @@ struct trusted_host { char *issuer; char *reason; unsigned long limit; - time_t issued; - time_t expires; + unsigned long issued; + unsigned long expires; }; struct gag_entry { char *mask; char *owner; char *reason; - time_t expires; + unsigned long expires; struct gag_entry *next; }; @@ -327,10 +380,10 @@ opserv_free_hostinfo(void *data) typedef struct opservDiscrim { struct chanNode *channels[DISCRIM_MAX_CHANS]; unsigned int channel_count; - char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *reason, *accountmask; + char *mask_nick, *mask_ident, *mask_host, *mask_info, *server, *reason, *notice_target, *accountmask; irc_in_addr_t ip_mask; unsigned long limit; - time_t min_ts, max_ts; + unsigned long min_ts, max_ts; 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, match_trusted : 1, option_log : 1; @@ -379,8 +432,15 @@ opserv_free_user_alert(void *data) free(alert); } -#define opserv_debug(format...) do { if (opserv_conf.debug_channel) send_channel_notice(opserv_conf.debug_channel , opserv , ## format); } while (0) -#define opserv_alert(format...) do { if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel , opserv , ## format); } while (0) +#if defined(GCC_VARMACROS) +# define opserv_debug(ARGS...) do { if (opserv_conf.debug_channel) send_channel_notice(opserv_conf.debug_channel, opserv, ARGS); } while (0) +# define opserv_alert(ARGS...) do { if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel, opserv, ARGS); } while (0) +# define opserv_custom_alert(CHAN, ARGS...) do { if (CHAN) send_target_message(4, (CHAN), opserv, ARGS); else if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel, opserv, ARGS); } while (0) +#elif defined(C99_VARMACROS) +# define opserv_debug(...) do { if (opserv_conf.debug_channel) send_channel_notice(opserv_conf.debug_channel, opserv, __VA_ARGS__); } while (0) +# define opserv_alert(...) do { if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel, opserv, __VA_ARGS__); } while (0) +# define opserv_custom_alert(chan, ...) do { if (chan) send_target_message(4, chan, opserv, __VA_ARGS__); else if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel, opserv, __VA_ARGS__); } while (0) +#endif /* A lot of these commands are very similar to what ChanServ can do, * but OpServ can do them even on channels that aren't registered. @@ -432,11 +492,15 @@ static MODCMD_FUNC(cmd_chaninfo) const char *fmt; struct banNode *ban; struct modeNode *moden; + struct modeNode **members; + time_t feh; unsigned int n; + int show_oplevels; reply("OSMSG_CHANINFO_HEADER", channel->name); fmt = user_find_message(user, "OSMSG_CHANINFO_TIMESTAMP"); - strftime(buffer, sizeof(buffer), fmt, gmtime(&channel->timestamp)); + feh = channel->timestamp; + strftime(buffer, sizeof(buffer), fmt, gmtime(&feh)); send_message_type(4, user, cmd->parent->bot, "%s", buffer); irc_make_chanmode(channel, buffer); if (channel->bad_channel) @@ -445,7 +509,8 @@ static MODCMD_FUNC(cmd_chaninfo) reply("OSMSG_CHANINFO_MODES", buffer); if (channel->topic_time) { fmt = user_find_message(user, "OSMSG_CHANINFO_TOPIC"); - strftime(buffer, sizeof(buffer), fmt, gmtime(&channel->topic_time)); + feh = channel->topic_time; + strftime(buffer, sizeof(buffer), fmt, gmtime(&feh)); send_message_type(4, user, cmd->parent->bot, buffer, channel->topic_nick, channel->topic); } else { irc_fetchtopic(cmd->parent->bot, channel->name); @@ -456,7 +521,8 @@ static MODCMD_FUNC(cmd_chaninfo) 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)); + feh = ban->set; + strftime(buffer, sizeof(buffer), fmt, localtime(&feh)); send_message_type(4, user, cmd->parent->bot, buffer, ban->ban, ban->who); } } @@ -466,25 +532,30 @@ static MODCMD_FUNC(cmd_chaninfo) return 1; } reply("OSMSG_CHANINFO_USER_COUNT", channel->members.used); + + /* Create and sort the members array. */ + members = alloca(channel->members.used * sizeof(members[0])); + for (n=0; nmembers.used; n++) + members[n] = channel->members.list[n]; + qsort(members, channel->members.used, sizeof(members[0]), modeNode_sort); + + /* Display the array. */ + show_oplevels = (channel->members.used != 0) + && (members[0]->modes & MODE_CHANOP) + && (members[0]->oplevel < MAXOPLEVEL); for (n=0; nmembers.used; n++) { - moden = channel->members.list[n]; + moden = members[n]; if (moden->modes & MODE_CHANOP) { - if (moden->oplevel >= 0) + if (show_oplevels) 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]; - if ((moden->modes & (MODE_CHANOP|MODE_VOICE)) == MODE_VOICE) + } else if (moden->modes & 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_VOICE)) == 0) + else send_message_type(4, user, cmd->parent->bot, " %s (%s@%s)", moden->user->nick, moden->user->ident, moden->user->hostname); } + return 1; } @@ -556,7 +627,7 @@ static MODCMD_FUNC(cmd_clearmodes) return 0; } mod_chanmode_init(&change); - change.modes_clear = channel->modes; + change.modes_clear = channel->modes & ~MODE_REGISTERED; modcmd_chanmode_announce(&change); reply("OSMSG_CLEARMODES_DONE", channel->name); return 1; @@ -768,7 +839,7 @@ opserv_block(struct userNode *target, char *src_handle, char *reason, unsigned l "G-line requested by %s.", src_handle); if (!duration) duration = opserv_conf.block_gline_duration; - return gline_add(src_handle, mask, duration, reason, now, now, 1); + return gline_add(src_handle, mask, duration, reason, now, now, 0, 1); } static MODCMD_FUNC(cmd_block) @@ -806,7 +877,7 @@ static MODCMD_FUNC(cmd_block) offset = 3; } if(duration && duration != opserv_conf.block_gline_duration) { - // We require more access when the duration is not the default block duration. + /* We require more access when the duration is not the default block duration. */ gline_cmd = dict_find(cmd->parent->commands, "gline", NULL); if(!gline_cmd) { @@ -842,7 +913,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, now, 1); + gline = gline_add(user->handle_info->handle, argv[1], duration, reason, now, now, 0, 1); reply("OSMSG_GLINE_ISSUED", gline->target); return 1; } @@ -1001,10 +1072,42 @@ static MODCMD_FUNC(cmd_kick) reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); return 0; } + if (IsService(target)) { + reply("MSG_SERVICE_IMMUNE", target->nick); + return 0; + } KickChannelUser(target, channel, cmd->parent->bot, reason); return 1; } +static MODCMD_FUNC(cmd_forcekick) +{ + struct userNode *target; + char *reason; + + if (argc < 3) { + 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); + } + target = GetUserH(argv[1]); + if (!target) { + reply("MSG_NICK_UNKNOWN", argv[1]); + return 0; + } + if (!GetUserMode(channel, target)) { + reply("OSMSG_NOT_ON_CHANNEL", target->nick, channel->name); + return 0; + } + if (IsLocal(target)) { + reply("OSMSG_FORCEKICK_LOCAL", target->nick); + return 0; + } + irc_kick(cmd->parent->bot, target, channel, reason); + return 1; +} + static MODCMD_FUNC(cmd_kickall) { unsigned int limit, n, inchan; @@ -1129,7 +1232,7 @@ static MODCMD_FUNC(cmd_part) reply("OSMSG_NOT_ON_CHANNEL", cmd->parent->bot->nick, channel->name); return 0; } - reason = (argc < 3) ? "Leaving." : unsplit_string(argv+2, argc-2, NULL); + reason = (argc < 2) ? "Leaving." : unsplit_string(argv+1, argc-1, NULL); reply("OSMSG_LEAVING", channel->name); DelChannelUser(cmd->parent->bot, channel, reason, 0); return 1; @@ -1137,7 +1240,7 @@ static MODCMD_FUNC(cmd_part) static MODCMD_FUNC(cmd_mode) { - if (!modcmd_chanmode(argv+1, argc-1, MCP_ALLOW_OVB|MCP_KEY_FREE|MC_ANNOUNCE)) { + if (!modcmd_chanmode(argv+1, argc-1, MCP_ALLOW_OVB|MCP_KEY_FREE|MC_ANNOUNCE|MCP_OPERMODE)) { reply("MSG_INVALID_MODES", unsplit_string(argv+1, argc-1, NULL)); return 0; } @@ -1212,21 +1315,16 @@ static MODCMD_FUNC(cmd_whois) } reply("OSMSG_WHOIS_NICK", target->nick); reply("OSMSG_WHOIS_HOST", target->ident, target->hostname); - if (IsFakeHost(target)) + if (IsFakeIdent(target) && IsFakeHost(target)) + reply("OSMSG_WHOIS_FAKEIDENTHOST", target->fakeident, target->fakehost); + else if (IsFakeIdent(target)) + reply("OSMSG_WHOIS_FAKEIDENT", target->fakeident); + else if (IsFakeHost(target)) reply("OSMSG_WHOIS_FAKEHOST", target->fakehost); reply("OSMSG_WHOIS_IP", irc_ntoa(&target->ip)); if (target->modes) { - bpos = 0; + bpos = irc_user_modes(target, buffer, sizeof(buffer)); #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 (IsService(target)) buffer[bpos++] = 'k'; - if (IsDeaf(target)) buffer[bpos++] = 'd'; - if (IsNoChan(target)) buffer[bpos++] = 'n'; - if (IsHiddenHost(target)) buffer[bpos++] = 'x'; - if (IsNoIdle(target)) buffer[bpos++] = 'I'; if (IsGagged(target)) buffer_cat(" (gagged)"); if (IsRegistering(target)) buffer_cat(" (registered account)"); buffer[bpos] = 0; @@ -1241,7 +1339,7 @@ static MODCMD_FUNC(cmd_whois) reply("OSMSG_WHOIS_ACCOUNT", (target->handle_info ? target->handle_info->handle : "Not authenticated")); intervalString(buffer, now - target->timestamp, user->handle_info); reply("OSMSG_WHOIS_NICK_AGE", buffer); - if (target->channels.used <= MAX_CHANNELS_WHOIS) + if (target->channels.used <= MAX_CHANNELS_WHOIS || HANDLE_FLAGGED(user->handle_info, BOT)) opserv_ison(user, target, "OSMSG_WHOIS_CHANNELS"); else reply("OSMSG_WHOIS_HIDECHANS"); @@ -1369,7 +1467,9 @@ static MODCMD_FUNC(cmd_stats_links) { static MODCMD_FUNC(cmd_stats_max) { - reply("OSMSG_MAX_CLIENTS", max_clients, asctime(localtime(&max_clients_time))); + time_t feh; + feh = max_clients_time; + reply("OSMSG_MAX_CLIENTS", max_clients, asctime(localtime(&feh))); return 1; } @@ -1436,7 +1536,7 @@ static MODCMD_FUNC(cmd_stats_network2) { #endif tbl.contents[nn][1] = buffer; ofs = strlen(buffer) + 1; - intervalString(buffer + ofs, now - server->link, user->handle_info); + intervalString(buffer + ofs, now - server->link_time, user->handle_info); if (server->self_burst) strcat(buffer + ofs, " Bursting"); tbl.contents[nn][2] = buffer + ofs; @@ -1518,7 +1618,7 @@ static MODCMD_FUNC(cmd_stats_uplink) { static MODCMD_FUNC(cmd_stats_uptime) { extern int lines_processed; - extern time_t boot_time; + extern unsigned long boot_time; double kernel_time; double user_time; char uptime[INTERVALLEN]; @@ -1773,7 +1873,7 @@ opserv_part_channel(void *data) static int alert_check_user(const char *key, void *data, void *extra); -static int +static void opserv_new_user_check(struct userNode *user) { struct opserv_hostinfo *ohi; @@ -1782,11 +1882,11 @@ opserv_new_user_check(struct userNode *user) /* Check to see if we should ignore them entirely. */ if (IsLocal(user) || IsService(user)) - return 0; + return; /* Check for alerts, and stop if we find one that kills them. */ if (dict_foreach(opserv_user_alerts, alert_check_user, user)) - return 1; + return; /* Gag them if appropriate. */ for (gag = gagList; gag; gag = gag->next) { @@ -1832,11 +1932,9 @@ opserv_new_user_check(struct userNode *user) } else if (ohi->clients.used > limit) { char target[IRC_NTOP_MAX_SIZE + 3] = { '*', '@', '\0' }; strcpy(target + 2, addr); - gline_add(opserv->nick, target, opserv_conf.clone_gline_duration, "AUTO Excessive connections from a single host.", now, now, 1); + gline_add(opserv->nick, target, opserv_conf.clone_gline_duration, "AUTO Excessive connections from a single host.", now, now, 0, 1); } } - - return 0; } static void @@ -1940,7 +2038,7 @@ opserv_join_check(struct modeNode *mNode) dict_foreach(opserv_channel_alerts, alert_check_user, user); - if (channel->bad_channel) { + if (opserv && channel->bad_channel) { opserv_debug("Found $b%s$b in bad-word channel $b%s$b; removing the user.", user->nick, channel->name); if (channel->name[0] != '#') DelUser(user, opserv, 1, "OSMSG_ILLEGAL_KILL_REASON"); @@ -2009,7 +2107,6 @@ opserv_add_bad_word(struct svccmd *cmd, struct userNode *user, const char *new_b reply("OSMSG_BAD_NUKING", orig_bad); string_list_delete(opserv_bad_words, bad_idx); bad_idx--; - free(orig_bad); } return 1; } @@ -2054,18 +2151,18 @@ static MODCMD_FUNC(cmd_addbad) /* Scan for existing channels that match the new bad word. */ if (!bad_found) { for (it = dict_first(channels); it; it = iter_next(it)) { - struct chanNode *channel = iter_data(it); + struct chanNode *chan = iter_data(it); - if (!opserv_bad_channel(channel->name)) + if (!opserv_bad_channel(chan->name)) continue; - channel->bad_channel = 1; - if (channel->name[0] == '#') - opserv_shutdown_channel(channel, "OSMSG_ILLEGAL_REASON"); + chan->bad_channel = 1; + if (chan->name[0] == '#') + opserv_shutdown_channel(chan, "OSMSG_ILLEGAL_REASON"); else { unsigned int nn; - for (nn=0; nnmembers.used; nn++) { - struct userNode *user = channel->members.list[nn]->user; - DelUser(user, cmd->parent->bot, 1, "OSMSG_ILLEGAL_KILL_REASON"); + for (nn = 0; nn < chan->members.used; nn++) { + struct userNode *victim = chan->members.list[nn]->user; + DelUser(victim, cmd->parent->bot, 1, "OSMSG_ILLEGAL_KILL_REASON"); } } } @@ -2150,7 +2247,7 @@ opserv_expire_trusted_host(void *data) } static void -opserv_add_trusted_host(const char *ipaddr, unsigned int limit, const char *issuer, time_t issued, time_t expires, const char *reason) +opserv_add_trusted_host(const char *ipaddr, unsigned int limit, const char *issuer, unsigned long issued, unsigned long expires, const char *reason) { struct trusted_host *th; th = calloc(1, sizeof(*th)); @@ -2225,7 +2322,7 @@ static MODCMD_FUNC(cmd_edittrust) return 0; } count = strtoul(argv[2], &tmp, 10); - if (!count || *tmp) { + if (*tmp != '\0') { reply("OSMSG_BAD_NUMBER", argv[2]); return 0; } @@ -2502,8 +2599,8 @@ foreach_matching_user(const char *hostmask, discrim_search_func func, void *extr if (!self->uplink) return 0; discrim = calloc(1, sizeof(*discrim)); discrim->limit = dict_size(clients); - discrim->max_level = ~0; - discrim->max_ts = now; + discrim->max_level = UINT_MAX; + discrim->max_ts = ULONG_MAX; discrim->max_channels = INT_MAX; discrim->authed = -1; discrim->info_space = -1; @@ -2553,7 +2650,7 @@ gag_expire(void *data) } unsigned int -gag_create(const char *mask, const char *owner, const char *reason, time_t expires) +gag_create(const char *mask, const char *owner, const char *reason, unsigned long expires) { struct gag_entry *gag; @@ -2577,7 +2674,7 @@ add_gag_helper(const char *key, void *data, UNUSED_ARG(void *extra)) { struct record_data *rd = data; char *owner, *reason, *expstr; - time_t expires; + unsigned long expires; owner = database_get_data(rd->d.object, KEY_OWNER, RECDB_QSTRING); reason = database_get_data(rd->d.object, KEY_REASON, RECDB_QSTRING); @@ -2686,7 +2783,7 @@ trusted_host_read(const char *host, void *data, UNUSED_ARG(void *extra)) { struct record_data *rd = data; const char *limit, *str, *reason, *issuer; - time_t issued, expires; + unsigned long issued, expires; if (rd->type == RECDB_QSTRING) { /* old style host by itself */ @@ -2714,6 +2811,57 @@ trusted_host_read(const char *host, void *data, UNUSED_ARG(void *extra)) return 0; } +static void +opserv_add_devnull_class(const char *name, unsigned long modes, unsigned long maxchan, unsigned long maxsendq) +{ + struct devnull_class *th; + th = calloc(1, sizeof(*th)); + if (!th) + return; + th->name = strdup(name); + th->modes = modes; + th->maxchan = maxchan; + th->maxsendq = maxsendq; + dict_insert(opserv_devnull_classes, th->name, th); +} + +static void +free_devnull_class(void *data) +{ + struct devnull_class *th = data; + free(th->name); + free(th); +} + +static int +devnull_class_read(const char *name, void *data, UNUSED_ARG(void *extra)) +{ + struct record_data *rd = data; + const char *nameb = name, *str; + unsigned long modes, maxchan, maxsendq; + unsigned int ii; + + if (rd->type == RECDB_OBJECT) { + dict_t obj = GET_RECORD_OBJECT(rd); + /* new style structure */ + nameb = database_get_data(obj, KEY_DEVNULL_NAME, RECDB_QSTRING); + str = database_get_data(obj, KEY_DEVNULL_MODE, RECDB_QSTRING); + modes = 0; + if (str) { + for (ii=0; str[ii]; ii++) + modes |= 1 << (devnull_inverse_modes[(unsigned char)str[ii]] - 1); + } + str = database_get_data(obj, KEY_DEVNULL_MAXCHAN, RECDB_QSTRING); + maxchan = str ? ParseInterval(str) : 0; + str = database_get_data(obj, KEY_DEVNULL_MAXSENDQ, RECDB_QSTRING); + maxsendq = str ? ParseInterval(str) : 0; + } else + return 0; + + opserv_add_devnull_class(nameb, modes, maxchan, maxsendq); + return 0; +} + static int opserv_saxdb_read(struct dict *conf_db) { @@ -2758,6 +2906,8 @@ opserv_saxdb_read(struct dict *conf_db) } if ((object = database_get_data(conf_db, KEY_TRUSTED_HOSTS, RECDB_OBJECT))) dict_foreach(object, trusted_host_read, opserv_trusted_hosts); + if ((object = database_get_data(conf_db, KEY_DEVNULL_CLASSES, RECDB_OBJECT))) + dict_foreach(object, devnull_class_read, opserv_devnull_classes); if ((object = database_get_data(conf_db, KEY_GAGS, RECDB_OBJECT))) dict_foreach(object, add_gag_helper, NULL); if ((object = database_get_data(conf_db, KEY_ALERTS, RECDB_OBJECT))) @@ -2815,6 +2965,28 @@ opserv_saxdb_write(struct saxdb_context *ctx) } saxdb_end_record(ctx); } + /* devnull_classes */ + if (dict_size(opserv_devnull_classes)) { + saxdb_start_record(ctx, KEY_DEVNULL_CLASSES, 1); + for (it = dict_first(opserv_devnull_classes); it; it = iter_next(it)) { + struct devnull_class *th = iter_data(it); + saxdb_start_record(ctx, iter_key(it), 0); + if (th->name) saxdb_write_string(ctx, KEY_DEVNULL_NAME, th->name); + if (th->modes) { + int ii, flen; + char flags[50]; + for (ii=flen=0; devnull_modes[ii]; ++ii) + if (th->modes & (1 << ii)) + flags[flen++] = devnull_modes[ii]; + flags[flen] = 0; + saxdb_write_string(ctx, KEY_DEVNULL_MODE, flags); + } + if (th->maxchan) saxdb_write_int(ctx, KEY_DEVNULL_MAXCHAN, th->maxchan); + if (th->maxsendq) saxdb_write_int(ctx, KEY_DEVNULL_MAXSENDQ, th->maxsendq); + saxdb_end_record(ctx); + } + saxdb_end_record(ctx); + } /* gags */ if (gagList) { struct gag_entry *gag; @@ -2938,7 +3110,7 @@ static MODCMD_FUNC(cmd_set) static MODCMD_FUNC(cmd_settime) { const char *srv_name_mask = "*"; - time_t new_time = now; + unsigned long new_time = now; if (argc > 1) srv_name_mask = argv[1]; @@ -2957,8 +3129,8 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in discrim = calloc(1, sizeof(*discrim)); discrim->limit = 250; - discrim->max_level = ~0; - discrim->max_ts = INT_MAX; + discrim->max_level = UINT_MAX; + discrim->max_ts = ULONG_MAX; discrim->domain_depth = 2; discrim->max_channels = INT_MAX; discrim->authed = -1; @@ -3084,6 +3256,12 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in } else if (irccasecmp(argv[i], "reason") == 0) { discrim->reason = strdup(unsplit_string(argv+i+1, argc-i-1, NULL)); i = argc; + } else if (irccasecmp(argv[i], "notice_target") == 0 || irccasecmp(argv[i], "target") == 0) { + if (!IsChannelName(argv[i + 1])) { + send_message(user, opserv, "MSG_NOT_CHANNEL_NAME"); + goto fail; + } + discrim->notice_target = argv[++i]; } else if (irccasecmp(argv[i], "last") == 0) { discrim->min_ts = now - ParseInterval(argv[++i]); } else if ((irccasecmp(argv[i], "linked") == 0) @@ -3162,7 +3340,7 @@ opserv_discrim_create(struct userNode *user, unsigned int argc, char *argv[], in static int discrim_match(discrim_t discrim, struct userNode *user) { - unsigned int access, i; + unsigned int level, i; if ((user->timestamp < discrim->min_ts) || (user->timestamp > discrim->max_ts) @@ -3184,9 +3362,9 @@ discrim_match(discrim_t discrim, struct userNode *user) for(i = 0; i < discrim->channel_count; i++) if (!GetUserMode(discrim->channels[i], user)) return 0; - access = user->handle_info ? user->handle_info->opserv_level : 0; - if ((access < discrim->min_level) - || (access > discrim->max_level)) { + level = user->handle_info ? user->handle_info->opserv_level : 0; + if ((level < discrim->min_level) + || (level > discrim->max_level)) { return 0; } if (discrim->min_clones > 1) { @@ -3311,7 +3489,7 @@ is_oper_victim(struct userNode *user, struct userNode *target, int match_opers, || (target->handle_info && target->handle_info->opserv_level > user->handle_info->opserv_level)); - // If we don't need an ip check or want to hit opers or the the "cheap" check already disqualified the target, we are done. + /* If we don't need an ip check or want to hit opers or the the "cheap" check already disqualified the target, we are done. */ if (!check_ip || match_opers || !is_victim) return is_victim; @@ -3542,18 +3720,18 @@ typedef struct channel_discrim { char *name, *topic; unsigned int min_users, max_users; - time_t min_ts, max_ts; + unsigned long min_ts, max_ts; 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 time_t +static unsigned long smart_parse_time(const char *str) { /* If an interval-style string is given, treat as time before now. * If it's all digits, treat directly as a Unix timestamp. */ - return str[strspn(str, "0123456789")] ? (time_t)(now - ParseInterval(str)) : (time_t)atoi(str); + return str[strspn(str, "0123456789")] ? (now - ParseInterval(str)) : strtoul(str, NULL, 0); } static cdiscrim_t @@ -3564,9 +3742,8 @@ opserv_cdiscrim_create(struct userNode *user, unsigned int argc, char *argv[]) discrim = calloc(1, sizeof(*discrim)); discrim->limit = 25; - discrim->max_users = ~0; - /* So, time_t is frequently signed. Fun. */ - discrim->max_ts = (1ul << (CHAR_BIT * sizeof(time_t) - 1)) - 1; + discrim->max_users = UINT_MAX; + discrim->max_ts = ULONG_MAX; for (i = 0; i < argc; i++) { /* Assume all criteria require arguments. */ @@ -3749,17 +3926,23 @@ gtrace_print_func(struct gline *gline, void *extra) char issued[INTERVALLEN]; char lastmod[INTERVALLEN]; char expires[INTERVALLEN]; + char lifetime[INTERVALLEN]; intervalString(issued, now - gline->issued, xtra->user->handle_info); if (gline->lastmod) intervalString(lastmod, now - gline->lastmod, xtra->user->handle_info); else strcpy(lastmod, ""); - if (gline->expires) + intervalString(lifetime, gline->lifetime - now, xtra->user->handle_info); + if (!gline->expires) { + send_message(xtra->user, opserv, "OSMSG_GTRACE_FOREVER", gline->target, issued, gline->issuer, lastmod, NULL, gline->reason, lifetime); + } else if (gline->expires < now) { + intervalString(expires, now - gline->expires, xtra->user->handle_info); + send_message(xtra->user, opserv, "OSMSG_GTRACE_EXPIRED", gline->target, issued, gline->issuer, lastmod, expires, gline->reason, lifetime); + } else { /* must be in the future */ intervalString(expires, gline->expires - now, xtra->user->handle_info); - else - strcpy(expires, "never"); - send_message(xtra->user, opserv, "OSMSG_GTRACE_FORMAT", gline->target, issued, gline->issuer, lastmod, expires, gline->reason); + send_message(xtra->user, opserv, "OSMSG_GTRACE_FORMAT", gline->target, issued, gline->issuer, lastmod, expires, gline->reason, lifetime); + } } static MODCMD_FUNC(cmd_stats_glines) { @@ -3881,7 +4064,7 @@ alert_check_user(const char *key, void *data, void *extra) log_module(OS_LOG, LOG_ERROR, "Invalid reaction type %d for alert %s.", alert->reaction, key); /* fall through to REACT_NOTICE case */ case REACT_NOTICE: - opserv_alert("Alert $b%s$b triggered by user $b%s$b!%s@%s (%s).", key, user->nick, user->ident, user->hostname, alert->discrim->reason); + opserv_custom_alert(alert->discrim->notice_target, "Alert $b%s$b triggered by user $b%s$b!%s@%s (%s).", key, user->nick, user->ident, user->hostname, alert->discrim->reason); break; } return 0; @@ -3911,6 +4094,8 @@ opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_han || user->uplink->burst || !user->handle_info) return; + else if (IsBot(user)) + return; else if (user->handle_info->opserv_level) type = "OPER"; else if (IsNetworkHelper(user)) @@ -3921,11 +4106,16 @@ opserv_staff_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_han return; 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); + send_channel_message(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); + send_channel_message(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); +} - dict_foreach(opserv_account_alerts, alert_check_user, user); +static void +opserv_auth_alert(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) +{ + if (!user->uplink->burst && user->handle_info) + dict_foreach(opserv_account_alerts, alert_check_user, user); } static MODCMD_FUNC(cmd_log) @@ -4070,6 +4260,584 @@ static MODCMD_FUNC(cmd_delalert) return 1; } +static MODCMD_FUNC(cmd_listdevnull) +{ + struct helpfile_table tbl; + unsigned int count = 0, ii = 0; + char *on,*off,*half; + on = "X"; + off = "-"; + half = "1/2"; + + dict_iterator_t it; + for (it = dict_first(opserv_devnull_classes); it; it = iter_next(it)) { + count++; + } + tbl.length = count+1; + tbl.width = 15; + tbl.flags = 0; + tbl.flags = TABLE_NO_FREE; + tbl.contents = malloc(tbl.length * sizeof(tbl.contents[0])); + tbl.contents[0] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[0][0] = "Name"; + tbl.contents[0][1] = "MC"; + tbl.contents[0][2] = "UT"; + tbl.contents[0][3] = "FL"; + tbl.contents[0][4] = "CH"; + tbl.contents[0][5] = "IH"; + tbl.contents[0][6] = "SI"; + tbl.contents[0][7] = "IH²"; + tbl.contents[0][8] = "oC"; + tbl.contents[0][9] = "oM"; + tbl.contents[0][10] = "+k"; + tbl.contents[0][11] = "+S"; + tbl.contents[0][12] = "+X"; + tbl.contents[0][13] = "MaxQ"; + tbl.contents[0][14] = "OpMe"; + if(!count) + { + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + reply("MSG_NONE"); + free(tbl.contents[0]); + free(tbl.contents); + return 0; + } + for (it = dict_first(opserv_devnull_classes); it; it = iter_next(it)) { + struct devnull_class *th = iter_data(it); + tbl.contents[++ii] = malloc(tbl.width * sizeof(tbl.contents[0][0])); + tbl.contents[ii][0] = th->name; + if(DEVNULL_FLAGGED(th, MODE_A)) { + tbl.contents[ii][1] = strtab(th->maxchan); + } else { + tbl.contents[ii][1] = off; + } + if(DEVNULL_FLAGGED(th, MODE_B)) { + tbl.contents[ii][2] = on; + } else { + tbl.contents[ii][2] = off; + } + if(DEVNULL_FLAGGED(th, MODE_D)) { + tbl.contents[ii][3] = on; + } else if(DEVNULL_FLAGGED(th, MODE_C)) { + tbl.contents[ii][3] = half; + } else { + tbl.contents[ii][3] = off; + } + if(DEVNULL_FLAGGED(th, MODE_E)) { + tbl.contents[ii][4] = on; + } else { + tbl.contents[ii][4] = off; + } + if(DEVNULL_FLAGGED(th, MODE_F)) { + tbl.contents[ii][5] = on; + } else { + tbl.contents[ii][5] = off; + } + if(DEVNULL_FLAGGED(th, MODE_J)) { + tbl.contents[ii][6] = on; + } else { + tbl.contents[ii][6] = off; + } + if(DEVNULL_FLAGGED(th, MODE_K)) { + tbl.contents[ii][7] = on; + } else { + tbl.contents[ii][7] = off; + } + if(DEVNULL_FLAGGED(th, MODE_L)) { + tbl.contents[ii][8] = on; + } else { + tbl.contents[ii][8] = off; + } + if(DEVNULL_FLAGGED(th, MODE_M)) { + tbl.contents[ii][9] = on; + } else { + tbl.contents[ii][9] = off; + } + if(DEVNULL_FLAGGED(th, MODE_G)) { + tbl.contents[ii][10] = on; + } else { + tbl.contents[ii][10] = off; + } + if(DEVNULL_FLAGGED(th, MODE_I)) { + tbl.contents[ii][11] = on; + } else { + tbl.contents[ii][11] = off; + } + if(DEVNULL_FLAGGED(th, MODE_H)) { + tbl.contents[ii][12] = on; + } else { + tbl.contents[ii][12] = off; + } + if(DEVNULL_FLAGGED(th, MODE_N)) { + tbl.contents[ii][13] = on; + } else { + tbl.contents[ii][13] = off; + } + if(DEVNULL_FLAGGED(th, MODE_OPME)) { + tbl.contents[ii][14] = on; + } else { + tbl.contents[ii][14] = off; + } + } + table_send(cmd->parent->bot, user->nick, 0, NULL, tbl); + for(ii = 1; ii < tbl.length; ++ii) + { + free(tbl.contents[ii]); + } + free(tbl.contents[0]); + free(tbl.contents); + send_message_type(4, user, opserv,"-"); + /* + tbl.contents[0][1] = "MC"; + tbl.contents[0][2] = "UT"; + tbl.contents[0][3] = "FL"; + tbl.contents[0][4] = "CH"; + tbl.contents[0][5] = "IH"; + tbl.contents[0][6] = "SI"; + tbl.contents[0][7] = "IH²"; + tbl.contents[0][8] = "oC"; + tbl.contents[0][9] = "oM"; + tbl.contents[0][10] = "+k"; + tbl.contents[0][11] = "+S"; + tbl.contents[0][12] = "+X"; + tbl.contents[0][13] = "MaxQ"; + */ + send_message_type(4, user, opserv,"MC = MaxChan"); + send_message_type(4, user, opserv,"UT = UnlimitTargets"); + send_message_type(4, user, opserv,"FL = Flood (1 = 1/2 flood, X = unlimited)"); + send_message_type(4, user, opserv,"CH = Channel Hide (mode +n)"); + send_message_type(4, user, opserv,"IH = Idle Hide (mode +I)"); + send_message_type(4, user, opserv,"SI = See Idle"); + send_message_type(4, user, opserv,"IH² = Idle Hide (override SI)"); + send_message_type(4, user, opserv,"oC = Color override (mode +c)"); + send_message_type(4, user, opserv,"oM = AMsg override"); + send_message_type(4, user, opserv,"+k = ChanServ Mode (mode +k)"); + send_message_type(4, user, opserv,"+S = NetServ Mode (mode +S)"); + send_message_type(4, user, opserv,"+X = XtraOp Mode (mode +X)"); + send_message_type(4, user, opserv,"OpMe = ChanServ opme command"); + return 1; +} + +static MODCMD_FUNC(cmd_adddevnull) +{ + + if (dict_find(opserv_devnull_classes, argv[1], NULL)) { + reply("OSMSG_DEVNULL_FOUND", argv[1]); + return 0; + } + + opserv_add_devnull_class(argv[1], 0, 0, 0); + reply("OSMSG_DEVNULL_ADDED",argv[1]); + return 1; +} + + +static MODCMD_FUNC(cmd_deldevnull) +{ + unsigned int n; + + for (n=1; nname); + dict_remove(opserv_devnull_classes, argv[n]); + reply("OSMSG_DEVNULL_REMOVED",argv[n]); + } + return 1; +} + +static MODCMD_FUNC(cmd_renamedevnull) +{ + struct devnull_class *th; + if (dict_find(opserv_devnull_classes, argv[2], NULL)) { + reply("OSMSG_DEVNULL_FOUND", argv[2]); + return 0; + } + if ((th = dict_find(opserv_devnull_classes, argv[1], NULL))) { + opserv_add_devnull_class(argv[2], th->modes, th->maxchan, th->maxsendq); + nickserv_devnull_rename(th->name,argv[2]); + dict_remove(opserv_devnull_classes, argv[1]); + reply("OSMSG_DEVNULL_RENAMED",argv[1],argv[2]); + } else { + reply("OSMSG_DEVNULL_NOTFOUND", argv[1]); + return 0; + } + return 1; +} + +static MODCMD_FUNC(cmd_setdevnull) +{ + struct devnull_class *th; + unsigned int offset=0; + if ((th = dict_find(opserv_devnull_classes, argv[offset+1], NULL))) { + if (argc > 3) { + unsigned int ii; + for( ii = 0; argv[offset+2][ ii ]; ii++) + argv[offset+2][ ii ] = toupper( argv[offset+2][ ii ] ); + for( ii = 0; argv[offset+3][ ii ]; ii++) + argv[offset+3][ ii ] = toupper( argv[offset+3][ ii ] ); + if(!strcmp("CHANLIMIT",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_A); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + DEVNULL_SET_FLAG(th, MODE_A); + th->maxchan = strtoul(argv[offset+3], NULL, 0); + reply("OSMSG_DEVNULL_SET_DONE"); + } + } + else if(!strcmp("UNLIMITTARGET",argv[offset+2]) || !strcmp("UNLIMITEDTARGET",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_B); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_B); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("FLOOD",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_C); + DEVNULL_CLEAR_FLAG(th, MODE_D); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_D); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("HALF",argv[offset+3]) || !strcmp("2",argv[offset+3]) || !strcmp("1/2",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_C); + DEVNULL_CLEAR_FLAG(th, MODE_D); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("CHANHIDE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_E); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_E); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("IDLEHIDE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_F); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_F); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("CHSERVMODE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_G); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_G); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("XTRAOPMODE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_H); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_H); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("NETSERVMODE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_I); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_I); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("SEEIDLE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_J); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_J); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("FORCEIDLEHIDE",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_K); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_K); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("OVERRIDECC",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_L); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_L); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("OVERRIDENOAMSG",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_M); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_M); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } + else if(!strcmp("MAXSENDQ",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_N); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + DEVNULL_SET_FLAG(th, MODE_N); + th->maxsendq = strtoul(argv[offset+3], NULL, 0); + reply("OSMSG_DEVNULL_SET_DONE"); + } + } + else if(!strcmp("OPME",argv[offset+2])) { + if (!strcmp("OFF",argv[offset+3]) || !strcmp("0",argv[offset+3])) { + DEVNULL_CLEAR_FLAG(th, MODE_OPME); + reply("OSMSG_DEVNULL_SET_DONE"); + } else if (!strcmp("ON",argv[offset+3]) || !strcmp("1",argv[offset+3])) { + DEVNULL_SET_FLAG(th, MODE_OPME); + reply("OSMSG_DEVNULL_SET_DONE"); + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+3]); + } + } else { + reply("OSMSG_DEVNULL_SET_INVALID", argv[offset+2]); + } + + } else { + reply("OSMSG_DEVNULL_SET", th->name); + if(DEVNULL_FLAGGED(th, MODE_A)) { + reply("OSMSG_DEVNULL_SET_A_i", th->maxchan); + } else { + reply("OSMSG_DEVNULL_SET_A", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_B)) { + reply("OSMSG_DEVNULL_SET_B", "on"); + } else { + reply("OSMSG_DEVNULL_SET_B", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_D)) { + reply("OSMSG_DEVNULL_SET_C", "on"); + } else if(DEVNULL_FLAGGED(th, MODE_C)) { + reply("OSMSG_DEVNULL_SET_C", "half"); + } else { + reply("OSMSG_DEVNULL_SET_C", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_E)) { + reply("OSMSG_DEVNULL_SET_E", "on"); + } else { + reply("OSMSG_DEVNULL_SET_E", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_F)) { + reply("OSMSG_DEVNULL_SET_F", "on"); + } else { + reply("OSMSG_DEVNULL_SET_F", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_G)) { + reply("OSMSG_DEVNULL_SET_G", "on"); + } else { + reply("OSMSG_DEVNULL_SET_G", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_H)) { + reply("OSMSG_DEVNULL_SET_H", "on"); + } else { + reply("OSMSG_DEVNULL_SET_H", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_I)) { + reply("OSMSG_DEVNULL_SET_I", "on"); + } else { + reply("OSMSG_DEVNULL_SET_I", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_J)) { + reply("OSMSG_DEVNULL_SET_J", "on"); + } else { + reply("OSMSG_DEVNULL_SET_J", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_K)) { + reply("OSMSG_DEVNULL_SET_K", "on"); + } else { + reply("OSMSG_DEVNULL_SET_K", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_L)) { + reply("OSMSG_DEVNULL_SET_L", "on"); + } else { + reply("OSMSG_DEVNULL_SET_L", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_M)) { + reply("OSMSG_DEVNULL_SET_M", "on"); + } else { + reply("OSMSG_DEVNULL_SET_M", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_N)) { + reply("OSMSG_DEVNULL_SET_N_i", th->maxsendq); + } else { + reply("OSMSG_DEVNULL_SET_N", "off"); + } + if(DEVNULL_FLAGGED(th, MODE_OPME)) { + reply("OSMSG_DEVNULL_SET_OPME", "on"); + } else { + reply("OSMSG_DEVNULL_SET_OPME", "off"); + } + } + } else { + reply("OSMSG_DEVNULL_NOTFOUND", argv[offset+1]); + return 0; + } + return 1; +} + +int devnull_check(const char *name) { + if (dict_find(opserv_devnull_classes, name, NULL)) { + return 1; + } + return 0; +} + +struct devnull_class* + devnull_get(const char *name) { + return dict_find(opserv_devnull_classes, name, NULL); +} + +void operpart(struct chanNode *chan, struct userNode *user) +{ + if(opserv_conf.alert_channel && opserv_conf.staff_auth_force > 0 && + !(irccasecmp(chan->name,opserv_conf.alert_channel->name))) { + struct mod_chanmode *change; + change = find_matching_bans(&chan->banlist, user, NULL); //don't join them if they're banned (exceptions from forced join) + if(change) + return; + irc_svsjoin(opserv,user,chan); + } +} + +void operadd(struct userNode *user) +{ + if(opserv_conf.alert_channel && opserv_conf.staff_auth_force > 0) + irc_svsjoin(opserv,user,opserv_conf.alert_channel); +} + +void operdel(struct userNode *user) +{ + if(opserv_conf.alert_channel && opserv_conf.staff_auth_force == 2) + irc_kick(opserv, user, opserv_conf.alert_channel, "mode -o"); +} + +static MODCMD_FUNC(cmd_svsjoin) +{ + struct userNode *target; + if(!(target=GetUserH(argv[1]))) { + reply("OSMSG_SVSNONICK", argv[1]); + return 0; + } + if(!IsChannelName(argv[2])) + { + reply("MSG_NOT_CHANNEL_NAME"); + return 0; + } + irc_svsjoinchan(opserv,target,argv[2]); + reply("OSMSG_SVSJOIN",target->nick,argv[2]); + return 1; +} + +static MODCMD_FUNC(cmd_svsnick) +{ + struct userNode *target; + if(!(target=GetUserH(argv[1]))) { + reply("OSMSG_SVSNONICK", argv[1]); + return 0; + } + if(GetUserH(argv[2])) + { + reply("OSMSG_SVSNICKUSED",argv[2]); + return 0; + } + irc_svsnick(opserv,target,argv[2]); + reply("OSMSG_SVSNICK",target->nick,argv[2]); + return 1; +} + +static MODCMD_FUNC(cmd_svsmode) +{ + struct userNode *target; + char *modestr; + if(!(target=GetUserH(argv[1]))) { + reply("OSMSG_SVSNONICK", argv[1]); + return 0; + } + modestr = unsplit_string(argv + 2, argc - 2, NULL); + irc_svsmode(opserv,target,modestr); + reply("OSMSG_SVSMODE",modestr,target->nick); + return 1; +} + +static MODCMD_FUNC(cmd_simul) +{ + struct userNode *target; + char *line; + if(argc > 2) { + if(!(target=GetUserH(argv[1]))) { + reply("OSMSG_SVSNONICK", argv[1]); + return 0; + } + line = unsplit_string(argv + 2, argc - 2, NULL); + irc_simul(target,line); + reply("OSMSG_SIMUL",target->nick,line); + return 1; + } + return 0; +} + +static MODCMD_FUNC(cmd_relay) +{ + struct userNode *target; + char *line; + if(!(target=GetUserH(argv[1]))) { + reply("OSMSG_SVSNONICK", argv[1]); + return 0; + } + line = unsplit_string(argv + 2, argc - 2, NULL); + char sendline[512]; + if(channel) + sprintf(sendline, "relay %s %s :%s",user->nick,channel->name,line); + else + sprintf(sendline, "relay %s query :%s",user->nick,line); + irc_privmsg(opserv,target->numeric,sendline); + return 1; +} + static void opserv_conf_read(void) { @@ -4112,8 +4880,11 @@ opserv_conf_read(void) str2 = "+timns"; opserv_conf.staff_auth_channel = AddChannel(str, now, str2, NULL); AddChannelUser(opserv, opserv_conf.staff_auth_channel)->modes |= MODE_CHANOP; + str2 = database_get_data(conf_node, KEY_STAFF_AUTH_FORCE_OPS, RECDB_QSTRING); + opserv_conf.staff_auth_force = str2 ? atoi(str2) : 0; } else { opserv_conf.staff_auth_channel = NULL; + opserv_conf.staff_auth_force = 0; } str = database_get_data(conf_node, KEY_UNTRUSTED_MAX, RECDB_QSTRING); opserv_conf.untrusted_max = str ? strtoul(str, NULL, 0) : 5; @@ -4159,6 +4930,10 @@ opserv_db_init(void) { dict_delete(opserv_trusted_hosts); opserv_trusted_hosts = dict_new(); dict_set_free_data(opserv_trusted_hosts, free_trusted_host); + /* set up opserv_devnull_classes dict */ + dict_delete(opserv_devnull_classes); + opserv_devnull_classes = dict_new(); + dict_set_free_data(opserv_devnull_classes, free_devnull_class); /* set up opserv_chan_warn dict */ dict_delete(opserv_chan_warn); opserv_chan_warn = dict_new(); @@ -4194,6 +4969,7 @@ opserv_db_cleanup(void) free_string_list(opserv_bad_words); dict_delete(opserv_exempt_channels); dict_delete(opserv_trusted_hosts); + dict_delete(opserv_devnull_classes); unreg_del_user_func(opserv_user_cleanup); dict_delete(opserv_hostinfo_dict); dict_delete(opserv_nick_based_alerts); @@ -4218,6 +4994,13 @@ init_opserv(const char *nick) } conf_register_reload(opserv_conf_read); + unsigned int i; + /* set up handle_inverse_flags */ + memset(devnull_inverse_modes, 0, sizeof(devnull_inverse_modes)); + for (i=0; devnull_modes[i]; i++) { + devnull_inverse_modes[(unsigned char)devnull_modes[i]] = i + 1; + } + memset(level_strings, 0, sizeof(level_strings)); opserv_module = module_register("OpServ", OS_LOG, "opserv.help", opserv_help_expand); opserv_define_func("ACCESS", cmd_access, 0, 0, 0); @@ -4260,6 +5043,7 @@ init_opserv(const char *nick) opserv_define_func("JUMP", cmd_jump, 900, 0, 2); opserv_define_func("JUPE", cmd_jupe, 900, 0, 4); opserv_define_func("KICK", cmd_kick, 100, 2, 2); + opserv_define_func("FORCEKICK", cmd_forcekick, 800, 2, 2); opserv_define_func("KICKALL", cmd_kickall, 400, 2, 0); opserv_define_func("KICKBAN", cmd_kickban, 100, 2, 2); opserv_define_func("KICKBANALL", cmd_kickbanall, 450, 2, 0); @@ -4295,6 +5079,16 @@ init_opserv(const char *nick) #if defined(WITH_MALLOC_SRVX) || defined(WITH_MALLOC_SLAB) opserv_define_func("STATS MEMORY", cmd_stats_memory, 0, 0, 0); #endif + opserv_define_func("DEVNULL ADD", cmd_adddevnull, 200, 0, 2); + opserv_define_func("DEVNULL DEL", cmd_deldevnull, 200, 0, 2); + opserv_define_func("DEVNULL RENAME", cmd_renamedevnull, 200, 0, 3); + opserv_define_func("DEVNULL SET", cmd_setdevnull, 200, 0, 2); + opserv_define_func("DEVNULL LIST", cmd_listdevnull, 200, 0, 0); + opserv_define_func("SVSJOIN", cmd_svsjoin, 800, 0, 3); + opserv_define_func("SVSMODE", cmd_svsmode, 800, 0, 3); + opserv_define_func("SVSNICK", cmd_svsnick, 800, 0, 3); + opserv_define_func("RELAY", cmd_relay, 800, 0, 0); + opserv_define_func("SIMUL", cmd_simul, 999, 0, 2); 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); @@ -4325,6 +5119,7 @@ init_opserv(const char *nick) reg_del_channel_func(opserv_channel_delete); reg_join_func(opserv_join_check); reg_auth_func(opserv_staff_alert); + reg_auth_func(opserv_auth_alert); opserv_db_init(); saxdb_register("OpServ", opserv_saxdb_read, opserv_saxdb_write);