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;
#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)
+#define opserv_custom_alert(chan, format...) do { if (chan) send_target_message(4 , chan , opserv , ## format); else if (opserv_conf.alert_channel) send_channel_notice(opserv_conf.alert_channel , opserv , ## format); } while (0)
/* 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.
} 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)
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;
"$bKILL$b: Kill matching clients.",
"$bGLINE$b: Issue a gline for the client's host (by default, 1 hour long).",
"$bGAG$b: Gag all matching users (by default, does not expire).",
- "$bDOMAINS$b: Display counts of users in each domain (length specified by DEPTH criteria.",
+ "$bDOMAINS$b: Display counts of users in each domain (length specified by DEPTH criteria.",
"Note: By default, IRC operators are not affected by the KILL, GLINE or GAG actions. You can override this by specifying the $bABUSE OPERS$b criteria for a trace. Even if you do specify $bABUSE OPERS$b, it will not affect opers at your access level or above.");
"TRACE CRITERIA" ("$bTRACE CRITERIA$b",
"Criteria and values for $btrace$b (a search with $btrace$b must match all specified items):",
"$bCLONES$b min Ignore clients from hosts with fewer than this many connections.",
"$bINFO_SPACE$b yes/no Clients match only if their info starts with a space (' ') character.",
"$bABUSE OPERS$b Force adverse actions to affect opers as well.",
+ "$bABUSE TRUSTED$b Force adverse actions to affect users on trusted hosts as well.",
+ "$bTARGET$b Send alert notice to this channel.",
"$bLOG$b Record matching users in $O's log file (in addition to acting).",
"Additionally, the $bCHANNEL$b target may be prefixed with @ to select channel operators, + to select voiced users (will not select chanops unless @ is also used), or - to select non-voiced non-chanop users. For example, CHANNEL #foo will select all users in #foo; CHANNEL +#foo will select only users voiced in #foo; CHANNEL @+#foo will select ops and voiced users in #foo; etc.");
"WHOIS" ("/msg $O WHOIS <nick>",