Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48f1bb2ce9 | ||
|
|
ddfbdc1277 |
No files matched your search
@@ -359,11 +359,16 @@ func (c *Conn) deliverKickMsg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deliverInviteMsg sends an INVITE line from the inviter
|
// deliverInviteMsg sends an INVITE line from the inviter
|
||||||
// for the channel named in text.
|
// for the channel named in text, or nothing when text names
|
||||||
|
// no channel.
|
||||||
func (c *Conn) deliverInviteMsg(
|
func (c *Conn) deliverInviteMsg(
|
||||||
msg *db.IRCMessage,
|
msg *db.IRCMessage,
|
||||||
text string,
|
text string,
|
||||||
) {
|
) {
|
||||||
|
if text == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
nick := c.nick
|
nick := c.nick
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|||||||
@@ -211,6 +211,38 @@ func TestRelayModeParameters(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestRelayInviteWithoutChannel checks that an INVITE whose
|
||||||
|
// body names no channel sends the invited IRC listener user
|
||||||
|
// no INVITE line.
|
||||||
|
func TestRelayInviteWithoutChannel(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
env := newTestEnv(t)
|
||||||
|
|
||||||
|
bob := env.dial(t)
|
||||||
|
bob.register("bob")
|
||||||
|
|
||||||
|
// A nil body is stored as JSON null, which is not an array.
|
||||||
|
for _, body := range [][]string{nil, {}, {""}} {
|
||||||
|
env.queueMessage(t, "bob", "INVITE", "carol", "bob", body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The relay sends a user's queue in order, so this arrives
|
||||||
|
// after anything sent for the INVITEs above.
|
||||||
|
env.queueMessage(t, "bob", "PRIVMSG", "carol", "bob",
|
||||||
|
[]string{"the end"})
|
||||||
|
|
||||||
|
lines := bob.readUntil(func(l string) bool {
|
||||||
|
return strings.HasSuffix(l, " :the end")
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
if strings.Contains(line, " INVITE ") {
|
||||||
|
t.Errorf("got %q, want no INVITE line", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestRelayLineBreaks checks that a CR, LF or NUL in a stored
|
// TestRelayLineBreaks checks that a CR, LF or NUL in a stored
|
||||||
// body line, key or mask never reaches an IRC listener user
|
// body line, key or mask never reaches an IRC listener user
|
||||||
// as a line break, so no extra line arrives, and that a body
|
// as a line break, so no extra line arrives, and that a body
|
||||||
|
|||||||
+19
-5
@@ -300,11 +300,14 @@ function App() {
|
|||||||
nickRef.current = nick;
|
nickRef.current = nick;
|
||||||
}, [nick]);
|
}, [nick]);
|
||||||
|
|
||||||
// Persist joined channels.
|
// Persist joined channels, once logged in: before then only the
|
||||||
|
// Server tab exists, and writing would erase the saved channels
|
||||||
|
// that onLogin rejoins.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!loggedIn) return;
|
||||||
const channels = tabs.filter((t) => t.type === "channel").map((t) => t.name);
|
const channels = tabs.filter((t) => t.type === "channel").map((t) => t.name);
|
||||||
localStorage.setItem("neoirc_channels", JSON.stringify(channels));
|
localStorage.setItem("neoirc_channels", JSON.stringify(channels));
|
||||||
}, [tabs]);
|
}, [loggedIn, tabs]);
|
||||||
|
|
||||||
// Clear unread on tab switch.
|
// Clear unread on tab switch.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -463,6 +466,15 @@ function App() {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "MODE": {
|
||||||
|
// The body is the change, with its value where it has one:
|
||||||
|
// ["+o bob"], ["+m"], ["+k", "secretpass"].
|
||||||
|
const modes = Array.isArray(msg.body) ? msg.body.join(" ") : "";
|
||||||
|
const text = `${msg.from} sets mode ${modes} on ${msg.to}`;
|
||||||
|
if (msg.to) addMessage(msg.to, { ...base, text, system: true });
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 353: {
|
case 353: {
|
||||||
// RPL_NAMREPLY — each name is a hostmask (nick!user@host),
|
// RPL_NAMREPLY — each name is a hostmask (nick!user@host),
|
||||||
// prefixed with @ for an operator or + for a voiced member.
|
// prefixed with @ for an operator or + for a voiced member.
|
||||||
@@ -759,6 +771,11 @@ function App() {
|
|||||||
|
|
||||||
const onLogin = useCallback(
|
const onLogin = useCallback(
|
||||||
async (userNick, isResumed) => {
|
async (userNick, isResumed) => {
|
||||||
|
// Read before setLoggedIn(true): from then on the effect under
|
||||||
|
// "Persist joined channels" writes the open channel tabs over it.
|
||||||
|
const saved = JSON.parse(
|
||||||
|
localStorage.getItem("neoirc_channels") || "[]",
|
||||||
|
);
|
||||||
setNick(userNick);
|
setNick(userNick);
|
||||||
setLoggedIn(true);
|
setLoggedIn(true);
|
||||||
addSystemMessage("Server", `Connected as ${userNick}`);
|
addSystemMessage("Server", `Connected as ${userNick}`);
|
||||||
@@ -783,9 +800,6 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fresh session — join any previously saved channels.
|
// Fresh session — join any previously saved channels.
|
||||||
const saved = JSON.parse(
|
|
||||||
localStorage.getItem("neoirc_channels") || "[]",
|
|
||||||
);
|
|
||||||
for (const ch of saved) {
|
for (const ch of saved) {
|
||||||
try {
|
try {
|
||||||
await api("/messages", {
|
await api("/messages", {
|
||||||
|
|||||||
Reference in new issue
Block a user