diff --git a/bot/bot.go b/bot/bot.go index 46cf4ac..83826be 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -2,9 +2,7 @@ package bot import ( "context" - "errors" "fmt" - "strings" "sync" "github.com/getsentry/sentry-go" @@ -13,8 +11,6 @@ import ( "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" - - "gitlab.com/etke.cc/postmoogle/utils" ) // Bot represents matrix bot @@ -80,99 +76,6 @@ func (b *Bot) Start(statusMsg string) error { return b.lp.Start(statusMsg) } -func (b *Bot) email2content(email *utils.Email, cfg settings) *event.MessageEventContent { - var text strings.Builder - if !cfg.NoSender() { - text.WriteString("From: ") - text.WriteString(email.From) - text.WriteString("\n\n") - } - if !cfg.NoSubject() { - text.WriteString("# ") - text.WriteString(email.Subject) - text.WriteString("\n\n") - } - if email.HTML != "" && !cfg.NoHTML() { - text.WriteString(format.HTMLToMarkdown(email.HTML)) - } else { - text.WriteString(email.Text) - } - - content := format.RenderMarkdown(text.String(), true, true) - return &content -} - -// Send email to matrix room -func (b *Bot) Send(ctx context.Context, email *utils.Email) error { - roomID, ok := b.GetMapping(utils.Mailbox(email.To)) - if !ok { - return errors.New("room not found") - } - - cfg, err := b.getSettings(roomID) - if err != nil { - b.Error(ctx, roomID, "cannot get settings: %v", err) - } - - contentParsed := b.email2content(email, cfg) - content := &event.Content{ - Raw: map[string]interface{}{ - eventMessageIDkey: email.MessageID, - eventInReplyToKey: email.InReplyTo, - }, - Parsed: contentParsed, - } - - var threadID id.EventID - if email.InReplyTo != "" && !cfg.NoThreads() { - threadID = b.getThreadID(roomID, email.InReplyTo) - if threadID != "" { - contentParsed.SetRelatesTo(&event.RelatesTo{ - Type: event.RelThread, - EventID: threadID, - }) - b.setThreadID(roomID, email.MessageID, threadID) - } - } - eventID, serr := b.lp.Send(roomID, content) - if serr != nil { - return serr - } - - if threadID == "" { - b.setThreadID(roomID, email.MessageID, eventID) - threadID = eventID - } - - if !cfg.NoFiles() { - b.sendFiles(ctx, roomID, email.Files, threadID) - } - return nil -} - -func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, threadID id.EventID) { - for _, file := range files { - req := file.Convert() - resp, err := b.lp.GetClient().UploadMedia(req) - if err != nil { - b.Error(ctx, roomID, "cannot upload file %s: %v", req.FileName, err) - continue - } - _, err = b.lp.Send(roomID, &event.MessageEventContent{ - MsgType: event.MsgFile, - Body: req.FileName, - URL: resp.ContentURI.CUString(), - RelatesTo: &event.RelatesTo{ - Type: event.RelThread, - EventID: threadID, - }, - }) - if err != nil { - b.Error(ctx, roomID, "cannot send uploaded file %s: %v", req.FileName, err) - } - } -} - // GetMappings returns mapping of mailbox = room func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { v, ok := b.rooms.Load(mailbox) diff --git a/bot/email.go b/bot/email.go new file mode 100644 index 0000000..e4849af --- /dev/null +++ b/bot/email.go @@ -0,0 +1,101 @@ +package bot + +import ( + "context" + "errors" + "strings" + + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/format" + "maunium.net/go/mautrix/id" + + "gitlab.com/etke.cc/postmoogle/utils" +) + +func email2content(email *utils.Email, cfg settings, threadID id.EventID) *event.Content { + var text strings.Builder + if !cfg.NoSender() { + text.WriteString("From: ") + text.WriteString(email.From) + text.WriteString("\n\n") + } + if !cfg.NoSubject() { + text.WriteString("# ") + text.WriteString(email.Subject) + text.WriteString("\n\n") + } + if email.HTML != "" && !cfg.NoHTML() { + text.WriteString(format.HTMLToMarkdown(email.HTML)) + } else { + text.WriteString(email.Text) + } + + parsed := format.RenderMarkdown(text.String(), true, true) + parsed.RelatesTo = utils.RelatesTo(cfg.NoThreads(), threadID) + + content := event.Content{ + Raw: map[string]interface{}{ + eventMessageIDkey: email.MessageID, + eventInReplyToKey: email.InReplyTo, + }, + Parsed: parsed, + } + return &content +} + +// Send email to matrix room +func (b *Bot) Send(ctx context.Context, email *utils.Email) error { + roomID, ok := b.GetMapping(utils.Mailbox(email.To)) + if !ok { + return errors.New("room not found") + } + + cfg, err := b.getSettings(roomID) + if err != nil { + b.Error(ctx, roomID, "cannot get settings: %v", err) + } + + var threadID id.EventID + if email.InReplyTo != "" && !cfg.NoThreads() { + threadID = b.getThreadID(roomID, email.InReplyTo) + if threadID != "" { + b.setThreadID(roomID, email.MessageID, threadID) + } + } + + content := email2content(email, cfg, threadID) + eventID, serr := b.lp.Send(roomID, content) + if serr != nil { + return serr + } + + if threadID == "" && !cfg.NoThreads() { + b.setThreadID(roomID, email.MessageID, eventID) + threadID = eventID + } + + if !cfg.NoFiles() { + b.sendFiles(ctx, roomID, email.Files, cfg.NoThreads(), threadID) + } + return nil +} + +func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, noThreads bool, parentID id.EventID) { + for _, file := range files { + req := file.Convert() + resp, err := b.lp.GetClient().UploadMedia(req) + if err != nil { + b.Error(ctx, roomID, "cannot upload file %s: %v", req.FileName, err) + continue + } + _, err = b.lp.Send(roomID, &event.MessageEventContent{ + MsgType: event.MsgFile, + Body: req.FileName, + URL: resp.ContentURI.CUString(), + RelatesTo: utils.RelatesTo(noThreads, parentID), + }) + if err != nil { + b.Error(ctx, roomID, "cannot send uploaded file %s: %v", req.FileName, err) + } + } +} diff --git a/utils/matrix.go b/utils/matrix.go new file mode 100644 index 0000000..faa2a54 --- /dev/null +++ b/utils/matrix.go @@ -0,0 +1,26 @@ +package utils + +import ( + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" +) + +// RelatesTo block of matrix event content +func RelatesTo(noThreads bool, parentID id.EventID) *event.RelatesTo { + if parentID == "" { + return nil + } + + if noThreads { + return &event.RelatesTo{ + InReplyTo: &event.InReplyTo{ + EventID: parentID, + }, + } + } + + return &event.RelatesTo{ + Type: event.RelThread, + EventID: parentID, + } +}