~emersion/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH chathistorysync] Add support for draft/event-playback

Details
Message ID
<20240718071423.269935-1-jp@neverwas.me>
DKIM signature
pass
Download raw message
Hi, these changes appear to work for my purposes, but I'm only just trying them
out now. Perhaps others needing this functionality would like to as well. Thanks.

[PATCH] Add support for draft/event-playback

Details
Message ID
<20240718071423.269935-2-jp@neverwas.me>
In-Reply-To
<20240718071423.269935-1-jp@neverwas.me> (view parent)
DKIM signature
pass
Download raw message
Patch: +79 -1
This adds an -events option to log JOINs, PARTs, etc., as mentioned in [1].
The log formatting in WriteMessage is copied from formatMessage in
soju/msgstore/znclog. It differs only in ZNC 1.9-style "Joins:" lines for
logged-in users [2]. "Joins:" parsing in UnmarshalLine should not be affected.

[1] https://todo.sr.ht/~emersion/chathistorysync/1
[2] https://github.com/znc/znc/pull/1870
---
 client.go   | 14 ++++++++++++
 main.go     |  4 ++++
 msgstore.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/client.go b/client.go
index 318bf0c..2db24bd 100644
--- a/client.go
+++ b/client.go
@@ -45,6 +45,7 @@ type client struct {
	*ircConn

	Debug bool
	Events bool

	caps struct {
		chatHistory     bool
@@ -71,6 +72,9 @@ func dialTLS(addr string) (*client, error) {

func (c *client) Register(nick, pass, netid string) {
	caps := []string{"draft/chathistory", "sasl", "message-tags", "batch", "echo-message", "server-time", "causal.agency/passive", "soju.im/bouncer-networks"}
	if c.Events {
		caps = append(caps, "cap-notify", "draft/event-playback", "account-tag")
	}
	for _, name := range caps {
		c.WriteMessage(&irc.Message{
			Command: "CAP",
@@ -167,6 +171,16 @@ func (c *client) ReadMessage() (*message, error) {
					return nil, fmt.Errorf("server doesn't support SASL authentication")
				}
			}
		case "NEW":
			for _, name := range msg.Params[2:] {
				switch name {
				case "draft/event-playback", "message-tags", "account-tag":
					c.WriteMessage(&irc.Message{
						Command: "CAP",
						Params:  []string{"REQ", name},
					})
				}
			}
		}
	case "BATCH":
		name := strings.TrimLeft(msg.Params[0], "+-")
diff --git a/main.go b/main.go
index d6afc23..587cefb 100644
--- a/main.go
+++ b/main.go
@@ -41,8 +41,10 @@ type bouncerNetwork struct {
func main() {
	var afterStr string
	var debug bool
	var events bool
	flag.StringVar(&afterStr, "after", "", "Only fetch logs after the specified date (format: YYYY-MM-DD)")
	flag.BoolVar(&debug, "debug", false, "Enable debug logs")
	flag.BoolVar(&events, "events", false, "Record JOINs, PARTs, etc.")
	flag.Usage = func() {
		fmt.Fprint(flag.CommandLine.Output(), usage)
		flag.PrintDefaults()
@@ -109,6 +111,7 @@ func main() {
	defer c.Close()

	c.Debug = debug
	c.Events = events
	c.Register(nick, pass, "")
	waitRegistered(c)

@@ -125,6 +128,7 @@ func main() {
			}

			c.Debug = debug
			c.Events = events
			c.Register(nick, pass, network.id)
			waitRegistered(c)

diff --git a/msgstore.go b/msgstore.go
index 1b0f09c..6e696d4 100644
--- a/msgstore.go
+++ b/msgstore.go
@@ -78,6 +78,27 @@ func (mw *messageWriter) advance(t time.Time) error {
	return nil
}

// parseCTCPMessage is ParseCTCPMessage from git.sr.ht/~emersion/soju/xirc.
func parseCTCPMessage(msg *message) (cmd string, params string, ok bool) {
	if (msg.Command != "PRIVMSG" && msg.Command != "NOTICE") || len(msg.Params) < 2 {
		return "", "", false
	}
	text := msg.Params[1]

	if !strings.HasPrefix(text, "\x01") {
		return "", "", false
	}
	text = strings.Trim(text, "\x01")

	words := strings.SplitN(text, " ", 2)
	cmd = strings.ToUpper(words[0])
	if len(words) > 1 {
		params = words[1]
	}

	return cmd, params, true
}

func (mw *messageWriter) WriteMessage(msg *message) error {
	t := msg.time.Local()

@@ -96,10 +117,49 @@ func (mw *messageWriter) WriteMessage(msg *message) error {

	var s string
	switch msg.Command {
	case "NICK":
		s = fmt.Sprintf("*** %s is now known as %s", msg.Prefix.Name, msg.Params[0])
	case "JOIN":
		s = fmt.Sprintf("*** Joins: %s (%s@%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host)
		// ZNC 1.9 appends account: https://github.com/znc/znc/pull/1870.
		if account, ok := msg.Tags.GetTag("account"); ok {
			s += " " + account
		}
	case "PART":
		var reason string
		if len(msg.Params) > 1 {
			reason = msg.Params[1]
		}
		s = fmt.Sprintf("*** Parts: %s (%s@%s) (%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host, reason)
	case "KICK":
		nick := msg.Params[1]
		var reason string
		if len(msg.Params) > 2 {
			reason = msg.Params[2]
		}
		s = fmt.Sprintf("*** %s was kicked by %s (%s)", nick, msg.Prefix.Name, reason)
	case "QUIT":
		var reason string
		if len(msg.Params) > 0 {
			reason = msg.Params[0]
		}
		s = fmt.Sprintf("*** Quits: %s (%s@%s) (%s)", msg.Prefix.Name, msg.Prefix.User, msg.Prefix.Host, reason)
	case "TOPIC":
		var topic string
		if len(msg.Params) > 1 {
			topic = msg.Params[1]
		}
		s = fmt.Sprintf("*** %s changes topic to '%s'", msg.Prefix.Name, topic)
	case "MODE":
		s = fmt.Sprintf("*** %s sets mode: %s", msg.Prefix.Name, strings.Join(msg.Params[1:], " "))
	case "NOTICE":
		s = fmt.Sprintf("-%s- %s", msg.Prefix.Name, msg.Params[1])
	case "PRIVMSG":
		s = fmt.Sprintf("<%s> %s", msg.Prefix.Name, msg.Params[1])
		if cmd, params, ok := parseCTCPMessage(msg); ok && cmd == "ACTION" {
			s = fmt.Sprintf("* %s %s", msg.Prefix.Name, params)
		} else {
			s = fmt.Sprintf("<%s> %s", msg.Prefix.Name, msg.Params[1])
		}
	}
	if s == "" {
		return nil
-- 
2.45.2
Reply to thread Export thread (mbox)