2021-06-04 12:03:03 -04:00
|
|
|
import * as irc from "./lib/irc.js";
|
2021-03-02 16:46:48 -05:00
|
|
|
import Client from "./lib/client.js";
|
2021-01-22 12:29:22 -05:00
|
|
|
|
2020-07-13 11:22:24 -04:00
|
|
|
export const SERVER_BUFFER = "*";
|
|
|
|
|
2020-06-26 04:35:38 -04:00
|
|
|
export const BufferType = {
|
|
|
|
SERVER: "server",
|
|
|
|
CHANNEL: "channel",
|
|
|
|
NICK: "nick",
|
|
|
|
};
|
2020-06-24 10:56:28 -04:00
|
|
|
|
2021-06-03 05:46:50 -04:00
|
|
|
export const ServerStatus = Client.Status;
|
2020-06-24 10:56:28 -04:00
|
|
|
|
|
|
|
export const Unread = {
|
|
|
|
NONE: "",
|
|
|
|
MESSAGE: "message",
|
2020-06-29 05:08:47 -04:00
|
|
|
HIGHLIGHT: "highlight",
|
2020-06-24 10:56:28 -04:00
|
|
|
|
2021-05-31 12:26:04 -04:00
|
|
|
compare(a, b) {
|
2020-06-24 10:56:28 -04:00
|
|
|
const priority = {
|
2021-05-27 16:35:41 -04:00
|
|
|
[Unread.NONE]: 0,
|
2020-06-24 10:56:28 -04:00
|
|
|
[Unread.MESSAGE]: 1,
|
2020-06-29 05:08:47 -04:00
|
|
|
[Unread.HIGHLIGHT]: 2,
|
2020-06-24 10:56:28 -04:00
|
|
|
};
|
2021-05-31 12:26:04 -04:00
|
|
|
return priority[a] - priority[b];
|
|
|
|
},
|
|
|
|
union(a, b) {
|
|
|
|
return (Unread.compare(a, b) > 0) ? a : b;
|
2020-06-24 10:56:28 -04:00
|
|
|
},
|
|
|
|
};
|
2020-07-15 12:47:33 -04:00
|
|
|
|
2020-07-23 03:58:05 -04:00
|
|
|
export const ReceiptType = {
|
|
|
|
DELIVERED: "delivered",
|
|
|
|
READ: "read",
|
|
|
|
};
|
|
|
|
|
2020-07-15 12:47:33 -04:00
|
|
|
export function getNickURL(nick) {
|
2021-05-25 06:42:24 -04:00
|
|
|
return "irc:///" + encodeURIComponent(nick) + ",isuser";
|
2020-07-15 12:47:33 -04:00
|
|
|
}
|
|
|
|
|
2021-06-03 05:04:32 -04:00
|
|
|
export function getChannelURL(channel) {
|
|
|
|
return "irc:///" + encodeURIComponent(channel);
|
|
|
|
}
|
|
|
|
|
2020-07-15 12:47:33 -04:00
|
|
|
export function getBufferURL(buf) {
|
|
|
|
switch (buf.type) {
|
|
|
|
case BufferType.SERVER:
|
|
|
|
return "irc:///";
|
|
|
|
case BufferType.CHANNEL:
|
2021-06-03 05:04:32 -04:00
|
|
|
return getChannelURL(buf.name);
|
2020-07-15 12:47:33 -04:00
|
|
|
case BufferType.NICK:
|
|
|
|
return getNickURL(buf.name);
|
|
|
|
}
|
|
|
|
throw new Error("Unknown buffer type: " + buf.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getMessageURL(buf, msg) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let bufURL = getBufferURL(buf);
|
2020-07-21 08:48:04 -04:00
|
|
|
if (msg.tags.msgid) {
|
2021-05-25 06:46:00 -04:00
|
|
|
return bufURL + "?msgid=" + encodeURIComponent(msg.tags.msgid);
|
2020-07-21 08:48:04 -04:00
|
|
|
} else {
|
2021-05-25 06:46:00 -04:00
|
|
|
return bufURL + "?timestamp=" + encodeURIComponent(msg.tags.time);
|
2020-07-21 08:48:04 -04:00
|
|
|
}
|
2020-07-15 12:47:33 -04:00
|
|
|
}
|
2021-05-31 11:39:37 -04:00
|
|
|
|
2021-06-03 05:46:50 -04:00
|
|
|
export function getServerName(server, bouncerNetwork, isBouncer) {
|
2021-05-31 11:39:37 -04:00
|
|
|
if (bouncerNetwork && bouncerNetwork.name) {
|
|
|
|
return bouncerNetwork.name;
|
|
|
|
}
|
|
|
|
if (isBouncer) {
|
|
|
|
return "bouncer";
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let netName = server.isupport.get("NETWORK");
|
2021-05-31 11:39:37 -04:00
|
|
|
if (netName) {
|
|
|
|
return netName;
|
|
|
|
}
|
|
|
|
|
|
|
|
return "server";
|
|
|
|
}
|
2021-06-04 12:03:03 -04:00
|
|
|
|
|
|
|
function updateState(state, updater) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let updated;
|
2021-06-04 12:03:03 -04:00
|
|
|
if (typeof updater === "function") {
|
|
|
|
updated = updater(state, state);
|
|
|
|
} else {
|
|
|
|
updated = updater;
|
|
|
|
}
|
|
|
|
if (state === updated || !updated) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return { ...state, ...updated };
|
|
|
|
}
|
|
|
|
|
2021-06-04 12:37:34 -04:00
|
|
|
function isServerBuffer(buf) {
|
|
|
|
return buf.type == BufferType.SERVER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns 1 if a should appear after b, -1 if a should appear before b, or
|
|
|
|
* 0 otherwise. */
|
|
|
|
function compareBuffers(a, b) {
|
|
|
|
if (a.server != b.server) {
|
|
|
|
return a.server > b.server ? 1 : -1;
|
|
|
|
}
|
|
|
|
if (isServerBuffer(a) != isServerBuffer(b)) {
|
|
|
|
return isServerBuffer(b) ? 1 : -1;
|
|
|
|
}
|
|
|
|
if (a.name != b.name) {
|
|
|
|
return a.name > b.name ? 1 : -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-11 06:44:14 -04:00
|
|
|
function updateMembership(membership, letter, add, client) {
|
|
|
|
let prefix = client.isupport.get("PREFIX") || "";
|
|
|
|
|
|
|
|
let prefixPrivs = new Map(irc.parseMembershipModes(prefix).map((membership, i) => {
|
|
|
|
return [membership.prefix, i];
|
|
|
|
}));
|
|
|
|
|
|
|
|
if (add) {
|
|
|
|
let i = membership.indexOf(letter);
|
|
|
|
if (i < 0) {
|
|
|
|
membership += letter;
|
|
|
|
membership = Array.from(membership).sort((a, b) => {
|
|
|
|
return prefixPrivs.get(a) - prefixPrivs.get(b);
|
|
|
|
}).join("");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
membership = membership.replace(letter, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
return membership;
|
|
|
|
}
|
|
|
|
|
2021-06-04 13:07:14 -04:00
|
|
|
/* Insert a message in an immutable list of sorted messages. */
|
|
|
|
function insertMessage(list, msg) {
|
|
|
|
if (list.length == 0) {
|
|
|
|
return [msg];
|
|
|
|
} else if (list[list.length - 1].tags.time <= msg.tags.time) {
|
|
|
|
return list.concat(msg);
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let insertBefore = -1;
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
|
|
let other = list[i];
|
2021-06-04 13:07:14 -04:00
|
|
|
if (msg.tags.time < other.tags.time) {
|
|
|
|
insertBefore = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
console.assert(insertBefore >= 0, "");
|
|
|
|
|
|
|
|
list = [ ...list ];
|
|
|
|
list.splice(insertBefore, 0, msg);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let lastServerID = 0;
|
|
|
|
let lastBufferID = 0;
|
2021-06-11 04:58:09 -04:00
|
|
|
let lastMessageKey = 0;
|
2021-06-04 12:37:34 -04:00
|
|
|
|
2021-06-04 12:03:03 -04:00
|
|
|
export const State = {
|
|
|
|
updateServer(state, id, updater) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let server = state.servers.get(id);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!server) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let updated = updateState(server, updater);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!updated) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let servers = new Map(state.servers);
|
2021-06-04 12:03:03 -04:00
|
|
|
servers.set(id, updated);
|
|
|
|
return { servers };
|
|
|
|
},
|
|
|
|
updateBuffer(state, id, updater) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let buf = State.getBuffer(state, id);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!buf) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let updated = updateState(buf, updater);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!updated) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let buffers = new Map(state.buffers);
|
2021-06-04 12:03:03 -04:00
|
|
|
buffers.set(buf.id, updated);
|
|
|
|
return { buffers };
|
|
|
|
},
|
|
|
|
getActiveServerID(state) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let buf = state.buffers.get(state.activeBuffer);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!buf) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return buf.server;
|
|
|
|
},
|
|
|
|
getBuffer(state, id) {
|
|
|
|
switch (typeof id) {
|
|
|
|
case "number":
|
|
|
|
return state.buffers.get(id);
|
|
|
|
case "object":
|
|
|
|
if (id.id) {
|
|
|
|
return state.buffers.get(id.id);
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let serverID = id.server, name = id.name;
|
2021-06-04 12:03:03 -04:00
|
|
|
if (!serverID) {
|
|
|
|
serverID = State.getActiveServerID(state);
|
|
|
|
}
|
2021-06-10 03:25:17 -04:00
|
|
|
if (!name) {
|
|
|
|
name = SERVER_BUFFER;
|
|
|
|
}
|
2021-06-04 12:03:03 -04:00
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let cm = irc.CaseMapping.RFC1459;
|
|
|
|
let server = state.servers.get(serverID);
|
2021-06-04 12:03:03 -04:00
|
|
|
if (server) {
|
|
|
|
cm = irc.CaseMapping.byName(server.isupport.get("CASEMAPPING")) || cm;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let nameCM = cm(name);
|
|
|
|
for (let buf of state.buffers.values()) {
|
2021-06-04 12:03:03 -04:00
|
|
|
if (buf.server === serverID && cm(buf.name) === nameCM) {
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
default:
|
|
|
|
throw new Error("Invalid buffer ID type: " + (typeof id));
|
|
|
|
}
|
|
|
|
},
|
2021-06-10 04:54:33 -04:00
|
|
|
createServer(state) {
|
|
|
|
lastServerID++;
|
2021-06-10 12:11:11 -04:00
|
|
|
let id = lastServerID;
|
2021-06-10 04:54:33 -04:00
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let servers = new Map(state.servers);
|
2021-06-10 04:54:33 -04:00
|
|
|
servers.set(id, {
|
|
|
|
id,
|
|
|
|
status: ServerStatus.DISCONNECTED,
|
|
|
|
isupport: new Map(),
|
|
|
|
});
|
|
|
|
return [id, { servers }];
|
|
|
|
},
|
2021-06-04 12:37:34 -04:00
|
|
|
createBuffer(state, name, serverID, client) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let buf = State.getBuffer(state, { server: serverID, name });
|
2021-06-04 12:37:34 -04:00
|
|
|
if (buf) {
|
|
|
|
return [buf.id, null];
|
|
|
|
}
|
|
|
|
|
|
|
|
lastBufferID++;
|
2021-06-10 12:11:11 -04:00
|
|
|
let id = lastBufferID;
|
2021-06-04 12:37:34 -04:00
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let type;
|
2021-06-04 12:37:34 -04:00
|
|
|
if (name == SERVER_BUFFER) {
|
|
|
|
type = BufferType.SERVER;
|
|
|
|
} else if (client.isChannel(name)) {
|
|
|
|
type = BufferType.CHANNEL;
|
|
|
|
} else {
|
|
|
|
type = BufferType.NICK;
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let bufferList = Array.from(state.buffers.values());
|
2021-06-04 12:37:34 -04:00
|
|
|
bufferList.push({
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
type,
|
|
|
|
server: serverID,
|
|
|
|
serverInfo: null, // if server
|
|
|
|
topic: null, // if channel
|
|
|
|
members: new irc.CaseMapMap(null, client.cm), // if channel
|
|
|
|
who: null, // if nick
|
|
|
|
offline: false, // if nick
|
|
|
|
messages: [],
|
|
|
|
unread: Unread.NONE,
|
2021-08-24 07:59:33 -04:00
|
|
|
lastReadReceipt: null,
|
2021-06-04 12:37:34 -04:00
|
|
|
});
|
|
|
|
bufferList = bufferList.sort(compareBuffers);
|
2021-06-10 12:11:11 -04:00
|
|
|
let buffers = new Map(bufferList.map((buf) => [buf.id, buf]));
|
2021-06-04 12:37:34 -04:00
|
|
|
return [id, { buffers }];
|
|
|
|
},
|
2021-06-04 12:27:21 -04:00
|
|
|
handleMessage(state, msg, serverID, client) {
|
|
|
|
function updateServer(updater) {
|
|
|
|
return State.updateServer(state, serverID, updater);
|
|
|
|
}
|
|
|
|
function updateBuffer(name, updater) {
|
|
|
|
return State.updateBuffer(state, { server: serverID, name }, updater);
|
|
|
|
}
|
|
|
|
|
2021-06-04 13:45:51 -04:00
|
|
|
// Don't update our internal state if it's a chat history message
|
|
|
|
if (irc.findBatchByType(msg, "chathistory")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-24 06:53:46 -04:00
|
|
|
let target, channel, topic, targets;
|
2021-06-04 12:27:21 -04:00
|
|
|
switch (msg.command) {
|
|
|
|
case irc.RPL_MYINFO:
|
|
|
|
// TODO: parse available modes
|
2021-06-10 12:11:11 -04:00
|
|
|
let serverInfo = {
|
2021-06-04 12:27:21 -04:00
|
|
|
name: msg.params[1],
|
|
|
|
version: msg.params[2],
|
|
|
|
};
|
|
|
|
return updateBuffer(SERVER_BUFFER, { serverInfo });
|
|
|
|
case irc.RPL_ISUPPORT:
|
2021-06-10 12:11:11 -04:00
|
|
|
let buffers = new Map(state.buffers);
|
2021-06-04 12:27:21 -04:00
|
|
|
state.buffers.forEach((buf) => {
|
|
|
|
if (buf.server != serverID) {
|
|
|
|
return;
|
|
|
|
}
|
2021-06-10 12:11:11 -04:00
|
|
|
let members = new irc.CaseMapMap(buf.members, client.cm);
|
2021-06-04 12:27:21 -04:00
|
|
|
buffers.set(buf.id, { ...buf, members });
|
|
|
|
});
|
|
|
|
return {
|
|
|
|
buffers,
|
|
|
|
...updateServer({ isupport: new Map(client.isupport) }),
|
|
|
|
};
|
|
|
|
case irc.RPL_NOTOPIC:
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[1];
|
2021-06-04 12:27:21 -04:00
|
|
|
return updateBuffer(channel, { topic: null });
|
|
|
|
case irc.RPL_TOPIC:
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[1];
|
|
|
|
topic = msg.params[2];
|
2021-06-04 12:27:21 -04:00
|
|
|
return updateBuffer(channel, { topic });
|
|
|
|
case irc.RPL_TOPICWHOTIME:
|
|
|
|
// Ignore
|
|
|
|
break;
|
|
|
|
case irc.RPL_NAMREPLY:
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[2];
|
|
|
|
let membersList = msg.params[3].split(" ");
|
2021-06-04 12:27:21 -04:00
|
|
|
|
|
|
|
return updateBuffer(channel, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let members = new irc.CaseMapMap(buf.members);
|
2021-06-04 12:27:21 -04:00
|
|
|
membersList.forEach((s) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let member = irc.parseTargetPrefix(s);
|
2021-06-04 12:27:21 -04:00
|
|
|
members.set(member.name, member.prefix);
|
|
|
|
});
|
|
|
|
return { members };
|
|
|
|
});
|
|
|
|
case irc.RPL_ENDOFNAMES:
|
|
|
|
break;
|
|
|
|
case irc.RPL_WHOREPLY:
|
2021-06-10 12:11:11 -04:00
|
|
|
let last = msg.params[msg.params.length - 1];
|
|
|
|
let who = {
|
2021-06-04 12:27:21 -04:00
|
|
|
username: msg.params[2],
|
|
|
|
hostname: msg.params[3],
|
|
|
|
server: msg.params[4],
|
|
|
|
nick: msg.params[5],
|
|
|
|
away: msg.params[6] == 'G', // H for here, G for gone
|
|
|
|
realname: last.slice(last.indexOf(" ") + 1),
|
|
|
|
};
|
|
|
|
return updateBuffer(who.nick, { who, offline: false });
|
|
|
|
case irc.RPL_ENDOFWHO:
|
2021-06-11 06:44:14 -04:00
|
|
|
target = msg.params[1];
|
2021-06-04 12:27:21 -04:00
|
|
|
if (!client.isChannel(target) && target.indexOf("*") < 0) {
|
|
|
|
// Not a channel nor a mask, likely a nick
|
|
|
|
return updateBuffer(target, (buf) => {
|
|
|
|
// TODO: mark user offline if we have old WHO info but this
|
|
|
|
// WHO reply is empty
|
|
|
|
if (buf.who) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
return { offline: true };
|
|
|
|
});
|
|
|
|
}
|
|
|
|
break;
|
2021-06-04 12:53:06 -04:00
|
|
|
case "JOIN":
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[0];
|
2021-06-04 12:53:06 -04:00
|
|
|
|
|
|
|
if (client.isMyNick(msg.prefix.name)) {
|
2021-06-10 12:11:11 -04:00
|
|
|
let [id, update] = State.createBuffer(state, channel, serverID, client);
|
2021-06-04 12:53:06 -04:00
|
|
|
state = { ...state, ...update };
|
|
|
|
}
|
|
|
|
|
2021-06-10 12:11:11 -04:00
|
|
|
let update = updateBuffer(channel, (buf) => {
|
|
|
|
let members = new irc.CaseMapMap(buf.members);
|
2021-06-04 12:53:06 -04:00
|
|
|
members.set(msg.prefix.name, "");
|
|
|
|
return { members };
|
|
|
|
});
|
|
|
|
return { ...state, ...update };
|
|
|
|
case "PART":
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[0];
|
2021-06-04 12:53:06 -04:00
|
|
|
|
|
|
|
return updateBuffer(channel, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let members = new irc.CaseMapMap(buf.members);
|
2021-06-04 12:53:06 -04:00
|
|
|
members.delete(msg.prefix.name);
|
|
|
|
return { members };
|
|
|
|
});
|
2021-06-04 12:27:21 -04:00
|
|
|
case "KICK":
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[0];
|
|
|
|
let nick = msg.params[1];
|
2021-06-04 12:27:21 -04:00
|
|
|
|
|
|
|
return updateBuffer(channel, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let members = new irc.CaseMapMap(buf.members);
|
2021-06-04 12:27:21 -04:00
|
|
|
members.delete(nick);
|
|
|
|
return { members };
|
|
|
|
});
|
|
|
|
case "SETNAME":
|
|
|
|
return updateBuffer(msg.prefix.name, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let who = { ...buf.who, realname: msg.params[0] };
|
2021-06-04 12:27:21 -04:00
|
|
|
return { who };
|
|
|
|
});
|
|
|
|
case "AWAY":
|
2021-06-10 12:11:11 -04:00
|
|
|
let awayMessage = msg.params[0];
|
2021-06-04 12:27:21 -04:00
|
|
|
|
|
|
|
return updateBuffer(msg.prefix.name, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let who = { ...buf.who, away: !!awayMessage };
|
2021-06-04 12:27:21 -04:00
|
|
|
return { who };
|
|
|
|
});
|
2021-06-04 12:57:02 -04:00
|
|
|
case "TOPIC":
|
2021-06-10 12:11:11 -04:00
|
|
|
channel = msg.params[0];
|
|
|
|
topic = msg.params[1];
|
2021-06-04 12:57:02 -04:00
|
|
|
return updateBuffer(channel, { topic });
|
2021-06-11 06:44:14 -04:00
|
|
|
case "MODE":
|
|
|
|
target = msg.params[0];
|
|
|
|
|
|
|
|
if (!client.isChannel(target)) {
|
|
|
|
return; // TODO: handle user mode changes too
|
|
|
|
}
|
|
|
|
|
|
|
|
let prefix = client.isupport.get("PREFIX") || "";
|
|
|
|
let prefixByMode = new Map(irc.parseMembershipModes(prefix).map((membership) => {
|
|
|
|
return [membership.mode, membership.prefix];
|
|
|
|
}));
|
|
|
|
|
|
|
|
return updateBuffer(target, (buf) => {
|
|
|
|
let members = new irc.CaseMapMap(buf.members);
|
|
|
|
|
2021-06-11 06:54:42 -04:00
|
|
|
irc.forEachChannelModeUpdate(msg, client.isupport, (mode, add, arg) => {
|
2021-06-11 06:44:14 -04:00
|
|
|
if (prefixByMode.has(mode)) {
|
|
|
|
let nick = arg;
|
|
|
|
let membership = members.get(nick);
|
|
|
|
let letter = prefixByMode.get(mode);
|
|
|
|
members.set(nick, updateMembership(membership, letter, add, client));
|
|
|
|
}
|
2021-06-11 06:54:42 -04:00
|
|
|
});
|
2021-06-11 06:44:14 -04:00
|
|
|
|
|
|
|
return { members };
|
|
|
|
});
|
2021-08-24 06:53:46 -04:00
|
|
|
case irc.RPL_MONONLINE:
|
|
|
|
targets = msg.params[1].split(",");
|
|
|
|
|
|
|
|
for (let target of targets) {
|
|
|
|
let prefix = irc.parsePrefix(target);
|
|
|
|
let update = updateBuffer(prefix.name, (buf) => {
|
|
|
|
return { offline: false };
|
|
|
|
});
|
|
|
|
state = { ...state, ...update };
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
case irc.RPL_MONOFFLINE:
|
|
|
|
targets = msg.params[1].split(",");
|
|
|
|
|
|
|
|
for (let target of targets) {
|
|
|
|
let prefix = irc.parsePrefix(target);
|
|
|
|
let update = updateBuffer(prefix.name, (buf) => {
|
|
|
|
return { offline: true };
|
|
|
|
});
|
|
|
|
state = { ...state, ...update };
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
2021-06-04 12:27:21 -04:00
|
|
|
}
|
|
|
|
},
|
2021-06-04 13:07:14 -04:00
|
|
|
addMessage(state, msg, bufID) {
|
2021-06-11 04:58:09 -04:00
|
|
|
lastMessageKey++;
|
|
|
|
msg.key = lastMessageKey;
|
|
|
|
|
2021-06-04 13:07:14 -04:00
|
|
|
return State.updateBuffer(state, bufID, (buf) => {
|
2021-06-10 12:11:11 -04:00
|
|
|
let messages = insertMessage(buf.messages, msg);
|
2021-06-04 13:07:14 -04:00
|
|
|
return { messages };
|
|
|
|
});
|
|
|
|
},
|
2021-06-04 12:03:03 -04:00
|
|
|
};
|