Add support for /ignore, /unignore and /ignorelist commands
This commit is contained in:
parent
0de90daa64
commit
468427bfdb
@ -1248,15 +1248,18 @@ kbd {
|
||||
}
|
||||
|
||||
#chat table.channel-list,
|
||||
#chat table.ban-list {
|
||||
#chat table.ban-list,
|
||||
#chat table.ignore-list {
|
||||
margin: 5px 10px;
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
|
||||
#chat table.channel-list th,
|
||||
#chat table.ban-list th,
|
||||
#chat table.ignore-list th,
|
||||
#chat table.channel-list td,
|
||||
#chat table.ban-list td {
|
||||
#chat table.ban-list td,
|
||||
#chat.table.ignore-list td {
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
border-bottom: #eee 1px solid;
|
||||
@ -1270,7 +1273,9 @@ kbd {
|
||||
#chat table.channel-list .topic,
|
||||
#chat table.ban-list .hostmask,
|
||||
#chat table.ban-list .banned_by,
|
||||
#chat table.ban-list .banned_at {
|
||||
#chat table.ban-list .banned_at,
|
||||
#chat table.ignore-list .hostmask,
|
||||
#chat table.ignore-list .when {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,8 @@ const commands = [
|
||||
"/expand",
|
||||
"/ho",
|
||||
"/hs",
|
||||
"/ignore",
|
||||
"/ignorelist",
|
||||
"/invite",
|
||||
"/join",
|
||||
"/kick",
|
||||
@ -64,6 +66,7 @@ const commands = [
|
||||
"/slap",
|
||||
"/topic",
|
||||
"/unban",
|
||||
"/unignore",
|
||||
"/voice",
|
||||
"/whois",
|
||||
];
|
||||
|
@ -293,6 +293,23 @@ function addJoinItem() {
|
||||
});
|
||||
}
|
||||
|
||||
function addIgnoreListItem() {
|
||||
function ignorelist(itemData) {
|
||||
socket.emit("input", {
|
||||
target: parseInt(itemData, 10),
|
||||
text: "/ignorelist",
|
||||
});
|
||||
}
|
||||
|
||||
addContextMenuItem({
|
||||
check: (target) => target.hasClass("lobby"),
|
||||
className: "list",
|
||||
displayName: "List ignored users",
|
||||
data: (target) => target.data("id"),
|
||||
callback: ignorelist,
|
||||
});
|
||||
}
|
||||
|
||||
function addDefaultItems() {
|
||||
addWhoisItem();
|
||||
addQueryItem();
|
||||
@ -306,4 +323,5 @@ function addDefaultItems() {
|
||||
addChannelListItem();
|
||||
addBanListItem();
|
||||
addJoinItem();
|
||||
addIgnoreListItem();
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ function processReceivedMessage(data) {
|
||||
const container = channel.find(".messages");
|
||||
const activeChannelId = chat.find(".chan.active").data("id");
|
||||
|
||||
if (data.msg.type === "channel_list" || data.msg.type === "ban_list") {
|
||||
if (data.msg.type === "channel_list" || data.msg.type === "ban_list" || data.msg.type === "ignore_list") {
|
||||
$(container).empty();
|
||||
}
|
||||
|
||||
|
16
client/views/actions/ignore_list.tpl
Normal file
16
client/views/actions/ignore_list.tpl
Normal file
@ -0,0 +1,16 @@
|
||||
<table class="ignore-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="hostmask">Hostmask</th>
|
||||
<th class="when">Ignored At</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each ignored}}
|
||||
<tr>
|
||||
<td class="hostmask">{{hostmask}}</td>
|
||||
<td class="when">{{{localetime when}}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
@ -360,6 +360,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>/ignore nick</code>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>
|
||||
Block any messages from the specified user on the current network.
|
||||
This can be a nickname or a hostmask.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>/ignorelist</code>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>Load the list of ignored users for the current network.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>/join channel</code>
|
||||
@ -537,6 +557,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>/unignore nick</code>
|
||||
</div>
|
||||
<div class="description">
|
||||
<p>
|
||||
Unblock messages from the specified user on the current network.
|
||||
This can be a nickname or a hostmask.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="help-item">
|
||||
<div class="subject">
|
||||
<code>/voice nick [...nick]</code>
|
||||
|
@ -48,6 +48,7 @@ const inputs = [
|
||||
"away",
|
||||
"connect",
|
||||
"disconnect",
|
||||
"ignore",
|
||||
"invite",
|
||||
"kick",
|
||||
"mode",
|
||||
|
@ -33,6 +33,8 @@ const Helper = {
|
||||
ip2hex,
|
||||
mergeConfig,
|
||||
getDefaultNick,
|
||||
parseHostmask,
|
||||
compareHostmask,
|
||||
|
||||
password: {
|
||||
hash: passwordHash,
|
||||
@ -226,3 +228,43 @@ function mergeConfig(oldConfig, newConfig) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parseHostmask(hostmask) {
|
||||
let nick = "";
|
||||
let ident = "*";
|
||||
let hostname = "*";
|
||||
let parts = [];
|
||||
|
||||
// Parse hostname first, then parse the rest
|
||||
parts = hostmask.split("@");
|
||||
|
||||
if (parts.length >= 2) {
|
||||
hostname = parts[1] || "*";
|
||||
hostmask = parts[0];
|
||||
}
|
||||
|
||||
hostname = hostname.toLowerCase();
|
||||
|
||||
parts = hostmask.split("!");
|
||||
|
||||
if (parts.length >= 2) {
|
||||
ident = parts[1] || "*";
|
||||
hostmask = parts[0];
|
||||
}
|
||||
|
||||
ident = ident.toLowerCase();
|
||||
|
||||
nick = hostmask.toLowerCase() || "*";
|
||||
|
||||
const result = {
|
||||
nick: nick,
|
||||
ident: ident,
|
||||
hostname: hostname,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function compareHostmask(a, b) {
|
||||
return (a.nick.toLowerCase() === b.nick.toLowerCase() || a.nick === "*") && (a.ident.toLowerCase() === b.ident.toLowerCase() || a.ident === "*") && (a.hostname.toLowerCase() === b.hostname.toLowerCase() || a.hostname === "*");
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ Msg.Type = {
|
||||
TOPIC_SET_BY: "topic_set_by",
|
||||
WHOIS: "whois",
|
||||
BANLIST: "ban_list",
|
||||
IGNORELIST: "ignore_list",
|
||||
};
|
||||
|
||||
module.exports = Msg;
|
||||
|
@ -18,6 +18,7 @@ const filteredFromClient = {
|
||||
highlightRegex: true,
|
||||
irc: true,
|
||||
password: true,
|
||||
ignoreList: true,
|
||||
};
|
||||
|
||||
function Network(attr) {
|
||||
@ -41,6 +42,7 @@ function Network(attr) {
|
||||
NETWORK: "",
|
||||
},
|
||||
chanCache: [],
|
||||
ignoreList: [],
|
||||
});
|
||||
|
||||
if (!this.uuid) {
|
||||
@ -325,6 +327,7 @@ Network.prototype.export = function() {
|
||||
"commands",
|
||||
"ip",
|
||||
"hostname",
|
||||
"ignoreList",
|
||||
]);
|
||||
|
||||
network.channels = this.channels
|
||||
|
120
src/plugins/inputs/ignore.js
Normal file
120
src/plugins/inputs/ignore.js
Normal file
@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
|
||||
const Chan = require("../../models/chan");
|
||||
const Msg = require("../../models/msg");
|
||||
const Helper = require("../../helper");
|
||||
|
||||
exports.commands = [
|
||||
"ignore",
|
||||
"unignore",
|
||||
"ignorelist",
|
||||
];
|
||||
|
||||
exports.input = function(network, chan, cmd, args) {
|
||||
const client = this;
|
||||
let target;
|
||||
let hostmask;
|
||||
|
||||
if (cmd !== "ignorelist" && (args.length === 0 || args[0].trim().length === 0)) {
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: `Usage: /${cmd} <nick>[!ident][@host]`,
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd !== "ignorelist") {
|
||||
// Trim to remove any spaces from the hostmask
|
||||
target = args[0].trim();
|
||||
hostmask = Helper.parseHostmask(target);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case "ignore": {
|
||||
// IRC nicks are case insensitive
|
||||
if (hostmask.nick.toLowerCase() === network.nick.toLowerCase()) {
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: "You can't ignore yourself",
|
||||
}));
|
||||
} else if (!network.ignoreList.some(function(entry) {
|
||||
return Helper.compareHostmask(entry, hostmask);
|
||||
})) {
|
||||
hostmask.when = Date.now();
|
||||
network.ignoreList.push(hostmask);
|
||||
|
||||
client.save();
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: `\u0002${hostmask.nick}!${hostmask.ident}@${hostmask.hostname}\u000f added to ignorelist`,
|
||||
}));
|
||||
} else {
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: "The specified user/hostmask is already ignored",
|
||||
}));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "unignore": {
|
||||
const idx = network.ignoreList.findIndex(function(entry) {
|
||||
return Helper.compareHostmask(entry, hostmask);
|
||||
});
|
||||
|
||||
// Check if the entry exists before removing it, otherwise
|
||||
// let the user know.
|
||||
if (idx !== -1) {
|
||||
network.ignoreList.splice(idx, 1);
|
||||
client.save();
|
||||
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: `Successfully removed \u0002${hostmask.nick}!${hostmask.ident}@${hostmask.hostname}\u000f from ignorelist`,
|
||||
}));
|
||||
} else {
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: "The specified user/hostmask is not ignored",
|
||||
}));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "ignorelist":
|
||||
if (network.ignoreList.length === 0) {
|
||||
chan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.ERROR,
|
||||
text: "Ignorelist is empty",
|
||||
}));
|
||||
} else {
|
||||
const chanName = "Ignored users";
|
||||
let newChan = network.getChannel(chanName);
|
||||
|
||||
if (typeof newChan === "undefined") {
|
||||
newChan = client.createChannel({
|
||||
type: Chan.Type.SPECIAL,
|
||||
name: chanName,
|
||||
});
|
||||
client.emit("join", {
|
||||
network: network.uuid,
|
||||
chan: newChan.getFilteredClone(true),
|
||||
index: network.addChannel(newChan),
|
||||
});
|
||||
}
|
||||
|
||||
newChan.pushMessage(client, new Msg({
|
||||
type: Msg.Type.IGNORELIST,
|
||||
ignored: network.ignoreList.map((data) => ({
|
||||
hostmask: `${data.nick}!${data.ident}@${data.hostname}`,
|
||||
when: data.when,
|
||||
})),
|
||||
}), true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
@ -4,6 +4,7 @@ const Chan = require("../../models/chan");
|
||||
const Msg = require("../../models/msg");
|
||||
const LinkPrefetch = require("./link");
|
||||
const cleanIrcMessage = require("../../../client/js/libs/handlebars/ircmessageparser/cleanIrcMessage");
|
||||
const Helper = require("../../helper");
|
||||
const nickRegExp = /(?:\x03[0-9]{1,2}(?:,[0-9]{1,2})?)?([\w[\]\\`^{|}-]+)/g;
|
||||
|
||||
module.exports = function(irc, network) {
|
||||
@ -43,11 +44,20 @@ module.exports = function(irc, network) {
|
||||
let showInActive = false;
|
||||
const self = data.nick === irc.user.nick;
|
||||
|
||||
// Check if the sender is in our ignore list
|
||||
const shouldIgnore = network.ignoreList.some(function(entry) {
|
||||
return Helper.compareHostmask(entry, data);
|
||||
});
|
||||
|
||||
// Server messages go to server window, no questions asked
|
||||
if (data.from_server) {
|
||||
chan = network.channels[0];
|
||||
from = chan.getUser(data.nick);
|
||||
} else {
|
||||
if (shouldIgnore) {
|
||||
return;
|
||||
}
|
||||
|
||||
let target = data.target;
|
||||
|
||||
// If the message is targeted at us, use sender as target instead
|
||||
|
@ -47,6 +47,7 @@ describe("Network", function() {
|
||||
{name: "&secure", key: "bar"},
|
||||
{name: "PrivateChat", type: "query"},
|
||||
],
|
||||
ignoreList: [],
|
||||
});
|
||||
});
|
||||
|
||||
|
62
test/tests/hostmask.js
Normal file
62
test/tests/hostmask.js
Normal file
@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
|
||||
const expect = require("chai").expect;
|
||||
const Helper = require("../../src/helper");
|
||||
|
||||
describe("Hostmask", function() {
|
||||
it(".parseHostmask", function() {
|
||||
expect(Helper.parseHostmask("nick").nick).to.equal("nick");
|
||||
expect(Helper.parseHostmask("nick").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("nick").hostname).to.equal("*");
|
||||
|
||||
expect(Helper.parseHostmask("!user").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("!user").ident).to.equal("user");
|
||||
expect(Helper.parseHostmask("!user").hostname).to.equal("*");
|
||||
|
||||
expect(Helper.parseHostmask("@host").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("@host").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("@host").hostname).to.equal("host");
|
||||
|
||||
expect(Helper.parseHostmask("!").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("!").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("!").hostname).to.equal("*");
|
||||
|
||||
expect(Helper.parseHostmask("@").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("@").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("@").hostname).to.equal("*");
|
||||
|
||||
expect(Helper.parseHostmask("!@").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("!@").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("!@").hostname).to.equal("*");
|
||||
|
||||
expect(Helper.parseHostmask("nick!user@host").nick).to.equal("nick");
|
||||
expect(Helper.parseHostmask("nick!user@host").ident).to.equal("user");
|
||||
expect(Helper.parseHostmask("nick!user@host").hostname).to.equal("host");
|
||||
|
||||
expect(Helper.parseHostmask("nick!!!!@thing@@host").nick).to.equal("nick");
|
||||
expect(Helper.parseHostmask("nick!!!!@thing@@host").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("nick!!!!@thing@@host").hostname).to.equal("thing");
|
||||
|
||||
expect(Helper.parseHostmask("!!!!@thing@@host").nick).to.equal("*");
|
||||
expect(Helper.parseHostmask("!!!!@thing@@host").ident).to.equal("*");
|
||||
expect(Helper.parseHostmask("!!!!@thing@@host").hostname).to.equal("thing");
|
||||
|
||||
expect(Helper.parseHostmask("NiCK!uSEr@HOST").nick).to.equal("nick");
|
||||
expect(Helper.parseHostmask("NiCK!uSEr@HOST").ident).to.equal("user");
|
||||
expect(Helper.parseHostmask("NiCK!uSEr@HOST").hostname).to.equal("host");
|
||||
});
|
||||
|
||||
it(".compareHostmask (wildcard)", function() {
|
||||
const a = Helper.parseHostmask("nick!user@host");
|
||||
const b = Helper.parseHostmask("nick!*@*");
|
||||
expect(Helper.compareHostmask(b, a)).to.be.true;
|
||||
expect(Helper.compareHostmask(a, b)).to.be.false;
|
||||
});
|
||||
|
||||
it(".compareHostmask", function() {
|
||||
const a = Helper.parseHostmask("nick!user@host");
|
||||
const b = Helper.parseHostmask("NiCK!useR@HOST");
|
||||
expect(Helper.compareHostmask(b, a)).to.be.true;
|
||||
expect(Helper.compareHostmask(a, b)).to.be.true;
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user