Relay INVITE to IRC listener users as an INVITE line (closes #147) #180
@@ -2719,7 +2719,9 @@ Each line of a multi-line `body` reaches an IRC listener user as its own
|
|||||||
is sent, so it cannot start a line of its own. A mode change made over the HTTP
|
is sent, so it cannot start a line of its own. A mode change made over the HTTP
|
||||||
API reaches IRC listener members as an IRC `MODE` line with its value as a
|
API reaches IRC listener members as an IRC `MODE` line with its value as a
|
||||||
separate parameter, e.g. `MODE #general +k secretpass` or
|
separate parameter, e.g. `MODE #general +k secretpass` or
|
||||||
`MODE #general +o bob`.
|
`MODE #general +o bob`. An `INVITE` from either transport reaches the invited
|
||||||
|
IRC listener user as an IRC `INVITE` line from the inviter, e.g.
|
||||||
|
`:alice!alice@* INVITE bob #general`.
|
||||||
|
|
||||||
### Docker Usage
|
### Docker Usage
|
||||||
|
|
||||||
|
|||||||
@@ -1261,10 +1261,9 @@ func (c *Conn) handleInvite(
|
|||||||
irc.RplInviting, targetNick, channel,
|
irc.RplInviting, targetNick, channel,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Send INVITE notice to target via service fan-out.
|
// Queue the INVITE to the target with the body the HTTP
|
||||||
body, _ := json.Marshal( //nolint:errchkjson
|
// API uses.
|
||||||
[]string{"You have been invited to " + channel},
|
body, _ := json.Marshal([]string{channel}) //nolint:errchkjson
|
||||||
)
|
|
||||||
|
|
||||||
_, _, _ = c.svc.FanOut( //nolint:dogsled // fire-and-forget broadcast
|
_, _, _ = c.svc.FanOut( //nolint:dogsled // fire-and-forget broadcast
|
||||||
ctx, "INVITE", c.nick, targetNick, targetID, 0,
|
ctx, "INVITE", c.nick, targetNick, targetID, 0,
|
||||||
|
|||||||
@@ -1373,6 +1373,42 @@ func TestIntegrationInviteUserOnChannel(t *testing.T) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestIntegrationInviteLine checks that an IRC listener user
|
||||||
|
// invited by an IRC listener user, and then over the HTTP
|
||||||
|
// API, gets an INVITE line from the inviter for the channel
|
||||||
|
// each time.
|
||||||
|
func TestIntegrationInviteLine(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
env := newTestEnv(t)
|
||||||
|
|
||||||
|
alice := env.dial(t)
|
||||||
|
alice.register("alice")
|
||||||
|
alice.joinAndDrain("#inv")
|
||||||
|
|
||||||
|
bob := env.dial(t)
|
||||||
|
bob.register("bob")
|
||||||
|
|
||||||
|
alice.sendAndExpect("INVITE bob #inv", " 341 ")
|
||||||
|
|
||||||
|
got := bob.readLine()
|
||||||
|
want := ":alice!alice@* INVITE bob #inv"
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("from the IRC listener: got %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The HTTP API queues an INVITE with the channel as its body.
|
||||||
|
env.queueMessage(t, "bob", "INVITE", "carol", "bob", []string{"#inv"})
|
||||||
|
|
||||||
|
got = bob.readLine()
|
||||||
|
want = ":carol!carol@* INVITE bob #inv"
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("over the HTTP API: got %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TestIntegrationModeSecretList checks that LIST shows a +s
|
// TestIntegrationModeSecretList checks that LIST shows a +s
|
||||||
// channel only to its members.
|
// channel only to its members.
|
||||||
func TestIntegrationModeSecretList(t *testing.T) {
|
func TestIntegrationModeSecretList(t *testing.T) {
|
||||||
|
|||||||
@@ -358,16 +358,24 @@ func (c *Conn) deliverKickMsg(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliverInviteMsg sends an INVITE notification.
|
// deliverInviteMsg sends an INVITE line from the inviter
|
||||||
|
// for the channel named in text, or nothing when text names
|
||||||
|
// no channel.
|
||||||
func (c *Conn) deliverInviteMsg(
|
func (c *Conn) deliverInviteMsg(
|
||||||
_ *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()
|
||||||
|
|
||||||
c.sendFromServer("NOTICE", nick, text)
|
prefix := msg.From + "!" + msg.From + "@*"
|
||||||
|
|
||||||
|
c.send(FormatMessage(prefix, "INVITE", nick, text))
|
||||||
}
|
}
|
||||||
|
|
||||||
// deliverWallops sends a WALLOPS notification.
|
// deliverWallops sends a WALLOPS notification.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user