diff --git a/README.md b/README.md index a37a778..65e9402 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ If you want to change them - check available options in the help message (`!pm h * **`!pm autoreply`** - Get or set autoreply of the room (markdown supported) that will be sent on any new incoming email thread * **`!pm signature`** - Get or set signature of the room (markdown supported) +* **`!pm threadify`** - Get or set `threadify` of the room (`true` - send incoming email body in thread; `false` - send incoming email body as part of the message) * **`!pm nosend`** - Get or set `nosend` of the room (`true` - disable email sending; `false` - enable email sending) * **`!pm noreplies`** - Get or set `noreplies` of the room (`true` - ignore matrix replies; `false` - parse matrix replies) * **`!pm nosender`** - Get or set `nosender` of the room (`true` - hide email sender; `false` - show email sender) diff --git a/bot/command.go b/bot/command.go index 1261087..c100415 100644 --- a/bot/command.go +++ b/bot/command.go @@ -116,6 +116,15 @@ func (b *Bot) initCommands() commandList { sanitizer: func(s string) string { return s }, allowed: b.allowOwner, }, + { + key: config.RoomThreadify, + description: fmt.Sprintf( + "Get or set `%s` of the room (`true` - send incoming email body in thread; `false` - send incoming email body as part of the message)", + config.RoomThreadify, + ), + sanitizer: utils.SanitizeBoolString, + allowed: b.allowOwner, + }, { key: config.RoomNoSend, description: fmt.Sprintf( diff --git a/bot/config/room.go b/bot/config/room.go index f99a203..af9929e 100644 --- a/bot/config/room.go +++ b/bot/config/room.go @@ -22,6 +22,7 @@ const ( RoomSignature = "signature" RoomAutoreply = "autoreply" + RoomThreadify = "threadify" RoomNoCC = "nocc" RoomNoFiles = "nofiles" RoomNoHTML = "nohtml" @@ -79,6 +80,10 @@ func (s Room) Autoreply() string { return s.Get(RoomAutoreply) } +func (s Room) Threadify() bool { + return utils.Bool(s.Get(RoomThreadify)) +} + func (s Room) NoSend() bool { return utils.Bool(s.Get(RoomNoSend)) } @@ -193,6 +198,7 @@ func (s Room) ContentOptions() *email.ContentOptions { Recipient: !s.NoRecipient(), Subject: !s.NoSubject(), Threads: !s.NoThreads(), + Threadify: s.Threadify(), ToKey: "cc.etke.postmoogle.to", CcKey: "cc.etke.postmoogle.cc", diff --git a/bot/email.go b/bot/email.go index 9c0adbb..80066be 100644 --- a/bot/email.go +++ b/bot/email.go @@ -154,6 +154,13 @@ func (b *Bot) IncomingEmail(ctx context.Context, eml *email.Email) error { b.setThreadID(roomID, eml.MessageID, threadID) b.setLastEventID(roomID, threadID, eventID) + if newThread && cfg.Threadify() { + _, berr := b.lp.Send(roomID, eml.ContentBody(threadID, cfg.ContentOptions())) + if berr != nil { + return berr + } + } + if !cfg.NoInlines() { b.sendFiles(ctx, roomID, eml.InlineFiles, cfg.NoThreads(), threadID) } diff --git a/email/email.go b/email/email.go index 8e507df..b4ad425 100644 --- a/email/email.go +++ b/email/email.go @@ -132,8 +132,15 @@ func (e *Email) contentHeader(threadID id.EventID, text *strings.Builder, option text.WriteString("\n\n") } if options.Subject && threadID == "" { - text.WriteString("# ") - text.WriteString(e.Subject) + if options.Threadify { + text.WriteString("**") + text.WriteString(e.Subject) + text.WriteString("**") + } else { + text.WriteString("# ") + text.WriteString(e.Subject) + + } text.WriteString("\n\n") } } @@ -144,10 +151,12 @@ func (e *Email) Content(threadID id.EventID, options *ContentOptions) *event.Con e.contentHeader(threadID, &text, options) - if e.HTML != "" && options.HTML { - text.WriteString(format.HTMLToMarkdown(e.HTML)) - } else { - text.WriteString(e.Text) + if threadID != "" || (threadID == "" && !options.Threadify) { + if e.HTML != "" && options.HTML { + text.WriteString(format.HTMLToMarkdown(e.HTML)) + } else { + text.WriteString(e.Text) + } } parsed := format.RenderMarkdown(text.String(), true, true) @@ -174,6 +183,28 @@ func (e *Email) Content(threadID id.EventID, options *ContentOptions) *event.Con return &content } +// ContentBody converts the email object to a Matrix event content that contains email body only +// NOTE: returns nil if threadify is disabled +func (e *Email) ContentBody(threadID id.EventID, options *ContentOptions) *event.Content { + if !options.Threadify { + return nil + } + var text string + if e.HTML != "" && options.HTML { + text = format.HTMLToMarkdown(e.HTML) + } else { + text = e.Text + } + + parsed := format.RenderMarkdown(text, true, true) + parsed.RelatesTo = linkpearl.RelatesTo(threadID, !options.Threads) + + content := event.Content{ + Parsed: &parsed, + } + return &content +} + // Compose converts the email object to a string (to be used for delivery via SMTP) and possibly DKIM-signs it func (e *Email) Compose(privkey string) string { textSize := len(e.Text) diff --git a/email/options.go b/email/options.go index c9fe79f..00e1210 100644 --- a/email/options.go +++ b/email/options.go @@ -18,6 +18,7 @@ type ContentOptions struct { Subject bool HTML bool Threads bool + Threadify bool // Keys MessageIDKey string