diff --git a/bot/access.go b/bot/access.go index 4a9b9d3..f943ae0 100644 --- a/bot/access.go +++ b/bot/access.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/getsentry/sentry-go" "github.com/raja/argon2pw" "gitlab.com/etke.cc/go/mxidwc" "maunium.net/go/mautrix/id" @@ -43,7 +42,7 @@ func (b *Bot) allowOwner(actorID id.UserID, targetRoomID id.RoomID) bool { } cfg, err := b.cfg.GetRoom(targetRoomID) if err != nil { - b.Error(sentry.SetHubOnContext(context.Background(), sentry.CurrentHub()), targetRoomID, "failed to retrieve settings: %v", err) + b.Error(context.Background(), "failed to retrieve settings: %v", err) return false } @@ -66,7 +65,7 @@ func (b *Bot) allowSend(actorID id.UserID, targetRoomID id.RoomID) bool { cfg, err := b.cfg.GetRoom(targetRoomID) if err != nil { - b.Error(sentry.SetHubOnContext(context.Background(), sentry.CurrentHub()), targetRoomID, "failed to retrieve settings: %v", err) + b.Error(context.Background(), "failed to retrieve settings: %v", err) return false } @@ -80,7 +79,7 @@ func (b *Bot) allowReply(actorID id.UserID, targetRoomID id.RoomID) bool { cfg, err := b.cfg.GetRoom(targetRoomID) if err != nil { - b.Error(sentry.SetHubOnContext(context.Background(), sentry.CurrentHub()), targetRoomID, "failed to retrieve settings: %v", err) + b.Error(context.Background(), "failed to retrieve settings: %v", err) return false } diff --git a/bot/bot.go b/bot/bot.go index b278ee2..a623731 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -6,11 +6,9 @@ import ( "regexp" "sync" - "github.com/getsentry/sentry-go" "github.com/rs/zerolog" "gitlab.com/etke.cc/linkpearl" "maunium.net/go/mautrix/event" - "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" "gitlab.com/etke.cc/postmoogle/bot/config" @@ -93,28 +91,21 @@ func New( } // Error message to the log and matrix room -func (b *Bot) Error(ctx context.Context, roomID id.RoomID, message string, args ...interface{}) { +func (b *Bot) Error(ctx context.Context, message string, args ...interface{}) { + evt := eventFromContext(ctx) err := fmt.Errorf(message, args...) - b.log.Error().Err(err).Msg("something is wrong") - - if roomID != "" { - b.SendError(ctx, roomID, err.Error()) + b.log.Error().Err(err).Msg(err.Error()) + if evt == nil { + return } -} -// SendError sends an error message to the matrix room -func (b *Bot) SendError(ctx context.Context, roomID id.RoomID, message string) { - b.SendNotice(ctx, roomID, "ERROR: "+message) -} - -// SendNotice sends a notice message to the matrix room -func (b *Bot) SendNotice(ctx context.Context, roomID id.RoomID, message string) { - parsed := format.RenderMarkdown(message, true, true) - parsed.MsgType = event.MsgNotice - _, err := b.lp.Send(roomID, &event.Content{Parsed: &parsed}) - if err != nil { - sentry.GetHubFromContext(ctx).CaptureException(err) + var noThreads bool + cfg, cerr := b.cfg.GetRoom(evt.RoomID) + if cerr == nil { + noThreads = cfg.NoThreads() } + + b.lp.SendNotice(evt.RoomID, "ERROR: "+err.Error(), utils.RelatesTo(!noThreads, evt.ID)) } // Start performs matrix /sync diff --git a/bot/command.go b/bot/command.go index 7948176..0134b8d 100644 --- a/bot/command.go +++ b/bot/command.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "gitlab.com/etke.cc/linkpearl" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" @@ -341,7 +342,7 @@ func (b *Bot) handle(ctx context.Context) { content := evt.Content.AsMessage() if content == nil { - b.Error(ctx, evt.RoomID, "cannot read message") + b.Error(ctx, "cannot read message") return } // ignore notices @@ -351,7 +352,7 @@ func (b *Bot) handle(ctx context.Context) { message := strings.TrimSpace(content.Body) commandSlice := b.parseCommand(message, true) if commandSlice == nil { - if utils.EventParent("", content) != "" { + if linkpearl.EventParent("", content) != "" { b.SendEmailReply(ctx) } return @@ -368,7 +369,7 @@ func (b *Bot) handle(ctx context.Context) { defer b.lp.GetClient().UserTyping(evt.RoomID, false, 30*time.Second) //nolint:errcheck if !cmd.allowed(evt.Sender, evt.RoomID) { - b.SendNotice(ctx, evt.RoomID, "not allowed to do that, kupo") + b.lp.SendNotice(evt.RoomID, "not allowed to do that, kupo") return } @@ -433,7 +434,7 @@ func (b *Bot) parseCommand(message string, toLower bool) []string { return strings.Split(strings.TrimSpace(message), " ") } -func (b *Bot) sendIntroduction(ctx context.Context, roomID id.RoomID) { +func (b *Bot) sendIntroduction(roomID id.RoomID) { var msg strings.Builder msg.WriteString("Hello, kupo!\n\n") @@ -449,7 +450,7 @@ func (b *Bot) sendIntroduction(ctx context.Context, roomID id.RoomID) { msg.WriteString(utils.EmailsList("SOME_INBOX", "")) msg.WriteString("` and have them appear in this room.") - b.SendNotice(ctx, roomID, msg.String()) + b.lp.SendNotice(roomID, msg.String()) } func (b *Bot) getHelpValue(cfg config.Room, cmd command) string { @@ -509,7 +510,7 @@ func (b *Bot) sendHelp(ctx context.Context) { msg.WriteString("\n") } - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) runSend(ctx context.Context) { @@ -521,7 +522,7 @@ func (b *Bot) runSend(ctx context.Context) { cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve room settings: %v", err) + b.Error(ctx, "failed to retrieve room settings: %v", err) return } @@ -539,10 +540,17 @@ func (b *Bot) getSendDetails(ctx context.Context) (string, string, string, bool) if !b.allowSend(evt.Sender, evt.RoomID) { return "", "", "", false } + + cfg, err := b.cfg.GetRoom(evt.RoomID) + if err != nil { + b.Error(ctx, "failed to retrieve room settings: %v", err) + return "", "", "", false + } + commandSlice := b.parseCommand(evt.Content.AsMessage().Body, false) to, subject, body, err := utils.ParseSend(commandSlice) if err == utils.ErrInvalidArgs { - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf( + b.lp.SendNotice(evt.RoomID, fmt.Sprintf( "Usage:\n"+ "```\n"+ "%s send someone@example.com\n"+ @@ -551,19 +559,15 @@ func (b *Bot) getSendDetails(ctx context.Context) (string, string, string, bool) "on as many lines\n"+ "as you want.\n"+ "```", - b.prefix)) - return "", "", "", false - } - - cfg, err := b.cfg.GetRoom(evt.RoomID) - if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve room settings: %v", err) + b.prefix), + utils.RelatesTo(!cfg.NoThreads(), evt.ID), + ) return "", "", "", false } mailbox := cfg.Mailbox() if mailbox == "" { - b.SendNotice(ctx, evt.RoomID, "mailbox is not configured, kupo") + b.lp.SendNotice(evt.RoomID, "mailbox is not configured, kupo", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return "", "", "", false } @@ -581,7 +585,7 @@ func (b *Bot) runSendCommand(ctx context.Context, cfg config.Room, tos []string, // validate first for _, to := range tos { if !email.AddressValid(to) { - b.Error(ctx, evt.RoomID, "email address is not valid") + b.Error(ctx, "email address is not valid") return } } @@ -597,22 +601,22 @@ func (b *Bot) runSendCommand(ctx context.Context, cfg config.Room, tos []string, eml := email.New(ID, "", " "+ID, subject, from, to, to, "", body, htmlBody, nil, nil) data := eml.Compose(b.cfg.GetBot().DKIMPrivateKey()) if data == "" { - b.SendError(ctx, evt.RoomID, "email body is empty") + b.lp.SendNotice(evt.RoomID, "email body is empty", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } queued, err := b.Sendmail(evt.ID, from, to, data) if queued { - b.log.Error().Err(err).Msg("cannot send email") + b.log.Warn().Err(err).Msg("email has been queued") b.saveSentMetadata(ctx, queued, evt.ID, recipients, eml, cfg) continue } if err != nil { - b.Error(ctx, evt.RoomID, "cannot send email to %s: %v", to, err) + b.Error(ctx, "cannot send email to %s: %v", to, err) continue } b.saveSentMetadata(ctx, false, evt.ID, recipients, eml, cfg) } if len(tos) > 1 { - b.SendNotice(ctx, evt.RoomID, "All emails were sent.") + b.lp.SendNotice(evt.RoomID, "All emails were sent.", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } } diff --git a/bot/command_admin.go b/bot/command_admin.go index a273c88..4f4f6fb 100644 --- a/bot/command_admin.go +++ b/bot/command_admin.go @@ -48,7 +48,7 @@ func (b *Bot) sendMailboxes(ctx context.Context) { sort.Strings(slice) if len(slice) == 0 { - b.SendNotice(ctx, evt.RoomID, "No mailboxes are managed by the bot so far, kupo!") + b.lp.SendNotice(evt.RoomID, "No mailboxes are managed by the bot so far, kupo!", utils.RelatesTo(true, evt.ID)) return } @@ -63,20 +63,20 @@ func (b *Bot) sendMailboxes(ctx context.Context) { msg.WriteString("\n") } - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) } func (b *Bot) runDelete(ctx context.Context, commandSlice []string) { evt := eventFromContext(ctx) if len(commandSlice) < 2 { - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Usage: `%s delete MAILBOX`", b.prefix)) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("Usage: `%s delete MAILBOX`", b.prefix), utils.RelatesTo(true, evt.ID)) return } mailbox := utils.Mailbox(commandSlice[1]) v, ok := b.rooms.Load(mailbox) if v == nil || !ok { - b.SendError(ctx, evt.RoomID, "mailbox does not exists, kupo") + b.lp.SendNotice(evt.RoomID, "mailbox does not exists, kupo", utils.RelatesTo(true, evt.ID)) return } roomID := v.(id.RoomID) @@ -84,11 +84,11 @@ func (b *Bot) runDelete(ctx context.Context, commandSlice []string) { b.rooms.Delete(mailbox) err := b.cfg.SetRoom(roomID, config.Room{}) if err != nil { - b.Error(ctx, evt.RoomID, "cannot update settings: %v", err) + b.Error(ctx, "cannot update settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "mailbox has been deleted") + b.lp.SendNotice(evt.RoomID, "mailbox has been deleted", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runUsers(ctx context.Context, commandSlice []string) { @@ -108,19 +108,19 @@ func (b *Bot) runUsers(ctx context.Context, commandSlice []string) { msg.WriteString("where each pattern is like `@someone:example.com`, ") msg.WriteString("`@bot.*:example.com`, `@*:another.com`, or `@*:*`\n") - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) return } _, homeserver, err := b.lp.GetClient().UserID.Parse() if err != nil { - b.SendError(ctx, evt.RoomID, fmt.Sprintf("invalid userID: %v", err)) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("invalid userID: %v", err), utils.RelatesTo(true, evt.ID)) } patterns := commandSlice[1:] allowedUsers, err := parseMXIDpatterns(patterns, "@*:"+homeserver) if err != nil { - b.SendError(ctx, evt.RoomID, fmt.Sprintf("invalid patterns: %v", err)) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("invalid patterns: %v", err), utils.RelatesTo(true, evt.ID)) return } @@ -128,10 +128,10 @@ func (b *Bot) runUsers(ctx context.Context, commandSlice []string) { err = b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set bot config: %v", err) + b.Error(ctx, "cannot set bot config: %v", err) } b.allowedUsers = allowedUsers - b.SendNotice(ctx, evt.RoomID, "allowed users updated") + b.lp.SendNotice(evt.RoomID, "allowed users updated", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runDKIM(ctx context.Context, commandSlice []string) { @@ -148,25 +148,27 @@ func (b *Bot) runDKIM(ctx context.Context, commandSlice []string) { var derr error signature, private, derr = secgen.DKIM() if derr != nil { - b.Error(ctx, evt.RoomID, "cannot generate DKIM signature: %v", derr) + b.Error(ctx, "cannot generate DKIM signature: %v", derr) return } cfg.Set(config.BotDKIMSignature, signature) cfg.Set(config.BotDKIMPrivateKey, private) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot save bot options: %v", err) + b.Error(ctx, "cannot save bot options: %v", err) return } } - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf( + b.lp.SendNotice(evt.RoomID, fmt.Sprintf( "DKIM signature is: `%s`.\n"+ "You need to add it to DNS records of all domains added to postmoogle (if not already):\n"+ "Add new DNS record with type = `TXT`, key (subdomain/from): `postmoogle._domainkey` and value (to):\n ```\n%s\n```\n"+ "Without that record other email servers may reject your emails as spam, kupo.\n"+ "To reset the signature, send `%s dkim reset`", - signature, signature, b.prefix)) + signature, signature, b.prefix), + utils.RelatesTo(true, evt.ID), + ) } func (b *Bot) runCatchAll(ctx context.Context, commandSlice []string) { @@ -189,25 +191,25 @@ func (b *Bot) runCatchAll(ctx context.Context, commandSlice []string) { msg.WriteString(" catch-all MAILBOX`") msg.WriteString("where mailbox is valid and existing mailbox name\n") - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) return } mailbox := utils.Mailbox(commandSlice[1]) _, ok := b.GetMapping(mailbox) if !ok { - b.SendError(ctx, evt.RoomID, "mailbox does not exist, kupo.") + b.lp.SendNotice(evt.RoomID, "mailbox does not exist, kupo.", utils.RelatesTo(true, evt.ID)) return } cfg.Set(config.BotCatchAll, mailbox) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot save bot options: %v", err) + b.Error(ctx, "cannot save bot options: %v", err) return } - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Catch-all is set to: `%s` (%s).", mailbox, utils.EmailsList(mailbox, ""))) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("Catch-all is set to: `%s` (%s).", mailbox, utils.EmailsList(mailbox, "")), utils.RelatesTo(true, evt.ID)) } func (b *Bot) runAdminRoom(ctx context.Context, commandSlice []string) { @@ -227,7 +229,7 @@ func (b *Bot) runAdminRoom(ctx context.Context, commandSlice []string) { msg.WriteString(" adminroom ROOM_ID`") msg.WriteString("where ROOM_ID is valid and existing matrix room id\n") - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) return } @@ -235,13 +237,13 @@ func (b *Bot) runAdminRoom(ctx context.Context, commandSlice []string) { cfg.Set(config.BotAdminRoom, roomID) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot save bot options: %v", err) + b.Error(ctx, "cannot save bot options: %v", err) return } b.adminRooms = append([]id.RoomID{id.RoomID(roomID)}, b.adminRooms...) // make it the first room in list on the fly - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Admin Room is set to: `%s`.", roomID)) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("Admin Room is set to: `%s`.", roomID), utils.RelatesTo(true, evt.ID)) } func (b *Bot) printGreylist(ctx context.Context, roomID id.RoomID) { @@ -272,7 +274,7 @@ func (b *Bot) printGreylist(ctx context.Context, roomID id.RoomID) { msg.WriteString("where `MIN` is duration in minutes for automatic greylisting\n") } - b.SendNotice(ctx, roomID, msg.String()) + b.lp.SendNotice(roomID, msg.String(), utils.RelatesTo(true, eventFromContext(ctx).ID)) } func (b *Bot) runGreylist(ctx context.Context, commandSlice []string) { @@ -286,9 +288,9 @@ func (b *Bot) runGreylist(ctx context.Context, commandSlice []string) { cfg.Set(config.BotGreylist, value) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set bot config: %v", err) + b.Error(ctx, "cannot set bot config: %v", err) } - b.SendNotice(ctx, evt.RoomID, "greylist duration has been updated") + b.lp.SendNotice(evt.RoomID, "greylist duration has been updated", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runBanlist(ctx context.Context, commandSlice []string) { @@ -316,7 +318,7 @@ func (b *Bot) runBanlist(ctx context.Context, commandSlice []string) { msg.WriteString("where each ip is IPv4 or IPv6\n\n") msg.WriteString("You can find current banlist values below:\n") - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) b.addBanlistTimeline(ctx) return } @@ -324,9 +326,9 @@ func (b *Bot) runBanlist(ctx context.Context, commandSlice []string) { cfg.Set(config.BotBanlistEnabled, value) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set bot config: %v", err) + b.Error(ctx, "cannot set bot config: %v", err) } - b.SendNotice(ctx, evt.RoomID, "banlist has been updated") + b.lp.SendNotice(evt.RoomID, "banlist has been updated", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runBanlistAuth(ctx context.Context, commandSlice []string) { @@ -344,16 +346,16 @@ func (b *Bot) runBanlistAuth(ctx context.Context, commandSlice []string) { msg.WriteString(" banlist:auth true` (banlist itself must be enabled!)\n\n") } - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) return } value := utils.SanitizeBoolString(commandSlice[1]) cfg.Set(config.BotBanlistAuth, value) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set bot config: %v", err) + b.Error(ctx, "cannot set bot config: %v", err) } - b.SendNotice(ctx, evt.RoomID, "auth banning has been updated") + b.lp.SendNotice(evt.RoomID, "auth banning has been updated", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runBanlistAuto(ctx context.Context, commandSlice []string) { @@ -371,16 +373,16 @@ func (b *Bot) runBanlistAuto(ctx context.Context, commandSlice []string) { msg.WriteString(" banlist:auto true` (banlist itself must be enabled!)\n\n") } - b.SendNotice(ctx, evt.RoomID, msg.String()) + b.lp.SendNotice(evt.RoomID, msg.String(), utils.RelatesTo(true, evt.ID)) return } value := utils.SanitizeBoolString(commandSlice[1]) cfg.Set(config.BotBanlistAuto, value) err := b.cfg.SetBot(cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set bot config: %v", err) + b.Error(ctx, "cannot set bot config: %v", err) } - b.SendNotice(ctx, evt.RoomID, "auto banning has been updated") + b.lp.SendNotice(evt.RoomID, "auto banning has been updated", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runBanlistAdd(ctx context.Context, commandSlice []string) { @@ -390,7 +392,7 @@ func (b *Bot) runBanlistAdd(ctx context.Context, commandSlice []string) { return } if !b.cfg.GetBot().BanlistEnabled() { - b.SendNotice(ctx, evt.RoomID, "banlist is disabled, you have to enable it first, kupo") + b.lp.SendNotice(evt.RoomID, "banlist is disabled, you have to enable it first, kupo", utils.RelatesTo(true, evt.ID)) return } banlist := b.cfg.GetBanlist() @@ -399,7 +401,7 @@ func (b *Bot) runBanlistAdd(ctx context.Context, commandSlice []string) { for _, ip := range ips { addr, err := net.ResolveIPAddr("ip", ip) if err != nil { - b.Error(ctx, evt.RoomID, "cannot add %s to banlist: %v", ip, err) + b.Error(ctx, "cannot add %s to banlist: %v", ip, err) return } banlist.Add(addr) @@ -407,11 +409,11 @@ func (b *Bot) runBanlistAdd(ctx context.Context, commandSlice []string) { err := b.cfg.SetBanlist(banlist) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set banlist: %v", err) + b.Error(ctx, "cannot set banlist: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "banlist has been updated, kupo") + b.lp.SendNotice(evt.RoomID, "banlist has been updated, kupo", utils.RelatesTo(true, evt.ID)) } func (b *Bot) runBanlistRemove(ctx context.Context, commandSlice []string) { @@ -421,7 +423,7 @@ func (b *Bot) runBanlistRemove(ctx context.Context, commandSlice []string) { return } if !b.cfg.GetBot().BanlistEnabled() { - b.SendNotice(ctx, evt.RoomID, "banlist is disabled, you have to enable it first, kupo") + b.lp.SendNotice(evt.RoomID, "banlist is disabled, you have to enable it first, kupo", utils.RelatesTo(true, evt.ID)) return } banlist := b.cfg.GetBanlist() @@ -430,7 +432,7 @@ func (b *Bot) runBanlistRemove(ctx context.Context, commandSlice []string) { for _, ip := range ips { addr, err := net.ResolveIPAddr("ip", ip) if err != nil { - b.Error(ctx, evt.RoomID, "cannot remove %s from banlist: %v", ip, err) + b.Error(ctx, "cannot remove %s from banlist: %v", ip, err) return } banlist.Remove(addr) @@ -438,11 +440,11 @@ func (b *Bot) runBanlistRemove(ctx context.Context, commandSlice []string) { err := b.cfg.SetBanlist(banlist) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set banlist: %v", err) + b.Error(ctx, "cannot set banlist: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "banlist has been updated, kupo") + b.lp.SendNotice(evt.RoomID, "banlist has been updated, kupo", utils.RelatesTo(true, evt.ID)) } func (b *Bot) addBanlistTimeline(ctx context.Context) { @@ -473,22 +475,22 @@ func (b *Bot) addBanlistTimeline(ctx context.Context) { txt.WriteString(strings.Join(data, "`, `")) txt.WriteString("`\n") } - b.SendNotice(ctx, evt.RoomID, txt.String()) + b.lp.SendNotice(evt.RoomID, txt.String(), utils.RelatesTo(true, evt.ID)) } } func (b *Bot) runBanlistReset(ctx context.Context) { evt := eventFromContext(ctx) if !b.cfg.GetBot().BanlistEnabled() { - b.SendNotice(ctx, evt.RoomID, "banlist is disabled, you have to enable it first, kupo") + b.lp.SendNotice(evt.RoomID, "banlist is disabled, you have to enable it first, kupo", utils.RelatesTo(true, evt.ID)) return } err := b.cfg.SetBanlist(config.List{}) if err != nil { - b.Error(ctx, evt.RoomID, "cannot set banlist: %v", err) + b.Error(ctx, "cannot set banlist: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "banlist has been reset, kupo") + b.lp.SendNotice(evt.RoomID, "banlist has been reset, kupo", utils.RelatesTo(true, evt.ID)) } diff --git a/bot/command_owner.go b/bot/command_owner.go index 6946b64..b26ce21 100644 --- a/bot/command_owner.go +++ b/bot/command_owner.go @@ -17,13 +17,13 @@ func (b *Bot) runStop(ctx context.Context) { evt := eventFromContext(ctx) cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve settings: %v", err) + b.Error(ctx, "failed to retrieve settings: %v", err) return } mailbox := cfg.Get(config.RoomMailbox) if mailbox == "" { - b.SendNotice(ctx, evt.RoomID, "that room is not configured yet") + b.lp.SendNotice(evt.RoomID, "that room is not configured yet", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } @@ -31,11 +31,11 @@ func (b *Bot) runStop(ctx context.Context) { err = b.cfg.SetRoom(evt.RoomID, config.Room{}) if err != nil { - b.Error(ctx, evt.RoomID, "cannot update settings: %v", err) + b.Error(ctx, "cannot update settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "mailbox has been disabled") + b.lp.SendNotice(evt.RoomID, "mailbox has been disabled", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) handleOption(ctx context.Context, cmd []string) { @@ -59,7 +59,7 @@ func (b *Bot) getOption(ctx context.Context, name string) { evt := eventFromContext(ctx) cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve settings: %v", err) + b.Error(ctx, "failed to retrieve settings: %v", err) return } @@ -72,7 +72,7 @@ func (b *Bot) getOption(ctx context.Context, name string) { msg := fmt.Sprintf("`%s` is not set, kupo.\n"+ "To set it, send a `%s %s VALUE` command.", name, b.prefix, name) - b.SendNotice(ctx, evt.RoomID, msg) + b.lp.SendNotice(evt.RoomID, msg, utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } @@ -90,20 +90,20 @@ func (b *Bot) getOption(ctx context.Context, name string) { "or just set a new one with `%s %s NEW_PASSWORD`.", b.prefix, name) } - b.SendNotice(ctx, evt.RoomID, msg) + b.lp.SendNotice(evt.RoomID, msg, utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) setMailbox(ctx context.Context, value string) { evt := eventFromContext(ctx) existingID, ok := b.getMapping(value) if (ok && existingID != "" && existingID != evt.RoomID) || b.isReserved(value) { - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Mailbox `%s` (%s) already taken, kupo", value, utils.EmailsList(value, ""))) + b.lp.SendNotice(evt.RoomID, fmt.Sprintf("Mailbox `%s` (%s) already taken, kupo", value, utils.EmailsList(value, ""))) return } cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve settings: %v", err) + b.Error(ctx, "failed to retrieve settings: %v", err) return } old := cfg.Get(config.RoomMailbox) @@ -118,37 +118,37 @@ func (b *Bot) setMailbox(ctx context.Context, value string) { err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot update settings: %v", err) + b.Error(ctx, "cannot update settings: %v", err) return } msg := fmt.Sprintf("mailbox of this room set to `%s`", value) - b.SendNotice(ctx, evt.RoomID, msg) + b.lp.SendNotice(evt.RoomID, msg, utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) setPassword(ctx context.Context) { evt := eventFromContext(ctx) cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve settings: %v", err) + b.Error(ctx, "failed to retrieve settings: %v", err) return } value := b.parseCommand(evt.Content.AsMessage().Body, false)[1] // get original value, without forced lower case value, err = argon2pw.GenerateSaltedHash(value) if err != nil { - b.Error(ctx, evt.RoomID, "failed to hash password: %v", err) + b.Error(ctx, "failed to hash password: %v", err) return } cfg.Set(config.RoomPassword, value) err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot update settings: %v", err) + b.Error(ctx, "cannot update settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "SMTP password has been set") + b.lp.SendNotice(evt.RoomID, "SMTP password has been set", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) setOption(ctx context.Context, name, value string) { @@ -160,7 +160,7 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { evt := eventFromContext(ctx) cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "failed to retrieve settings: %v", err) + b.Error(ctx, "failed to retrieve settings: %v", err) return } @@ -175,19 +175,19 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { old := cfg.Get(name) if old == value { - b.SendNotice(ctx, evt.RoomID, "nothing changed, kupo.") + b.lp.SendNotice(evt.RoomID, "nothing changed, kupo.", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } cfg.Set(name, value) err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot update settings: %v", err) + b.Error(ctx, "cannot update settings: %v", err) return } msg := fmt.Sprintf("`%s` of this room set to `%s`", name, value) - b.SendNotice(ctx, evt.RoomID, msg) + b.lp.SendNotice(evt.RoomID, msg, utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) runSpamlistAdd(ctx context.Context, commandSlice []string) { @@ -196,12 +196,12 @@ func (b *Bot) runSpamlistAdd(ctx context.Context, commandSlice []string) { b.getOption(ctx, config.RoomSpamlist) return } - roomCfg, err := b.cfg.GetRoom(evt.RoomID) + cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot get room settings: %v", err) + b.Error(ctx, "cannot get room settings: %v", err) return } - spamlist := utils.StringSlice(roomCfg[config.RoomSpamlist]) + spamlist := utils.StringSlice(cfg[config.RoomSpamlist]) for _, newItem := range commandSlice[1:] { newItem = strings.TrimSpace(newItem) if slices.Contains(spamlist, newItem) { @@ -210,14 +210,14 @@ func (b *Bot) runSpamlistAdd(ctx context.Context, commandSlice []string) { spamlist = append(spamlist, newItem) } - roomCfg.Set(config.RoomSpamlist, utils.SliceString(spamlist)) - err = b.cfg.SetRoom(evt.RoomID, roomCfg) + cfg.Set(config.RoomSpamlist, utils.SliceString(spamlist)) + err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot store room settings: %v", err) + b.Error(ctx, "cannot store room settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "spamlist has been updated, kupo") + b.lp.SendNotice(evt.RoomID, "spamlist has been updated, kupo", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) runSpamlistRemove(ctx context.Context, commandSlice []string) { @@ -226,13 +226,13 @@ func (b *Bot) runSpamlistRemove(ctx context.Context, commandSlice []string) { b.getOption(ctx, config.RoomSpamlist) return } - roomCfg, err := b.cfg.GetRoom(evt.RoomID) + cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot get room settings: %v", err) + b.Error(ctx, "cannot get room settings: %v", err) return } toRemove := map[int]struct{}{} - spamlist := utils.StringSlice(roomCfg[config.RoomSpamlist]) + spamlist := utils.StringSlice(cfg[config.RoomSpamlist]) for _, item := range commandSlice[1:] { item = strings.TrimSpace(item) idx := slices.Index(spamlist, item) @@ -242,7 +242,7 @@ func (b *Bot) runSpamlistRemove(ctx context.Context, commandSlice []string) { toRemove[idx] = struct{}{} } if len(toRemove) == 0 { - b.SendNotice(ctx, evt.RoomID, "nothing new, kupo.") + b.lp.SendNotice(evt.RoomID, "nothing new, kupo.", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } @@ -254,35 +254,35 @@ func (b *Bot) runSpamlistRemove(ctx context.Context, commandSlice []string) { updatedSpamlist = append(updatedSpamlist, item) } - roomCfg.Set(config.RoomSpamlist, utils.SliceString(updatedSpamlist)) - err = b.cfg.SetRoom(evt.RoomID, roomCfg) + cfg.Set(config.RoomSpamlist, utils.SliceString(updatedSpamlist)) + err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot store room settings: %v", err) + b.Error(ctx, "cannot store room settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "spamlist has been updated, kupo") + b.lp.SendNotice(evt.RoomID, "spamlist has been updated, kupo", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } func (b *Bot) runSpamlistReset(ctx context.Context) { evt := eventFromContext(ctx) - roomCfg, err := b.cfg.GetRoom(evt.RoomID) + cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot get room settings: %v", err) + b.Error(ctx, "cannot get room settings: %v", err) return } - spamlist := utils.StringSlice(roomCfg[config.RoomSpamlist]) + spamlist := utils.StringSlice(cfg[config.RoomSpamlist]) if len(spamlist) == 0 { - b.SendNotice(ctx, evt.RoomID, "spamlist is empty, kupo.") + b.lp.SendNotice(evt.RoomID, "spamlist is empty, kupo.", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } - roomCfg.Set(config.RoomSpamlist, "") - err = b.cfg.SetRoom(evt.RoomID, roomCfg) + cfg.Set(config.RoomSpamlist, "") + err = b.cfg.SetRoom(evt.RoomID, cfg) if err != nil { - b.Error(ctx, evt.RoomID, "cannot store room settings: %v", err) + b.Error(ctx, "cannot store room settings: %v", err) return } - b.SendNotice(ctx, evt.RoomID, "spamlist has been reset, kupo.") + b.lp.SendNotice(evt.RoomID, "spamlist has been reset, kupo.", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) } diff --git a/bot/config/manager.go b/bot/config/manager.go index 528498d..04112bd 100644 --- a/bot/config/manager.go +++ b/bot/config/manager.go @@ -32,7 +32,7 @@ func (m *Manager) GetBot() Bot { var config Bot config, err = m.lp.GetAccountData(acBotKey) if err != nil { - m.log.Error().Err(utils.UnwrapError(err)).Msg("cannot get bot settings") + m.log.Error().Err(err).Msg("cannot get bot settings") } if config == nil { config = make(Bot, 0) @@ -44,7 +44,7 @@ func (m *Manager) GetBot() Bot { // SetBot config func (m *Manager) SetBot(cfg Bot) error { - return utils.UnwrapError(m.lp.SetAccountData(acBotKey, cfg)) + return m.lp.SetAccountData(acBotKey, cfg) } // GetRoom config @@ -54,12 +54,12 @@ func (m *Manager) GetRoom(roomID id.RoomID) (Room, error) { config = make(Room, 0) } - return config, utils.UnwrapError(err) + return config, err } // SetRoom config func (m *Manager) SetRoom(roomID id.RoomID, cfg Room) error { - return utils.UnwrapError(m.lp.SetRoomAccountData(roomID, acRoomKey, cfg)) + return m.lp.SetRoomAccountData(roomID, acRoomKey, cfg) } // GetBanlist config @@ -72,7 +72,7 @@ func (m *Manager) GetBanlist() List { defer m.mu.Unlock("banlist") config, err := m.lp.GetAccountData(acBanlistKey) if err != nil { - m.log.Error().Err(utils.UnwrapError(err)).Msg("cannot get banlist") + m.log.Error().Err(err).Msg("cannot get banlist") } if config == nil { config = make(List, 0) @@ -93,14 +93,14 @@ func (m *Manager) SetBanlist(cfg List) error { cfg = make(List, 0) } - return utils.UnwrapError(m.lp.SetAccountData(acBanlistKey, cfg)) + return m.lp.SetAccountData(acBanlistKey, cfg) } // GetGreylist config func (m *Manager) GetGreylist() List { config, err := m.lp.GetAccountData(acGreylistKey) if err != nil { - m.log.Error().Err(utils.UnwrapError(err)).Msg("cannot get banlist") + m.log.Error().Err(err).Msg("cannot get banlist") } if config == nil { config = make(List, 0) @@ -112,5 +112,5 @@ func (m *Manager) GetGreylist() List { // SetGreylist config func (m *Manager) SetGreylist(cfg List) error { - return utils.UnwrapError(m.lp.SetAccountData(acGreylistKey, cfg)) + return m.lp.SetAccountData(acGreylistKey, cfg) } diff --git a/bot/email.go b/bot/email.go index b5798f9..9132b4c 100644 --- a/bot/email.go +++ b/bot/email.go @@ -5,6 +5,7 @@ import ( "errors" "strings" + "gitlab.com/etke.cc/linkpearl" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" "maunium.net/go/mautrix/id" @@ -120,7 +121,7 @@ func (b *Bot) IncomingEmail(ctx context.Context, email *email.Email) error { } cfg, err := b.cfg.GetRoom(roomID) if err != nil { - b.Error(ctx, roomID, "cannot get settings: %v", err) + b.Error(ctx, "cannot get settings: %v", err) } b.mu.Lock(roomID.String()) @@ -139,7 +140,7 @@ func (b *Bot) IncomingEmail(ctx context.Context, email *email.Email) error { eventID, serr := b.lp.Send(roomID, content) if serr != nil { if !strings.Contains(serr.Error(), "M_UNKNOWN") { // if it's not an unknown event event error - return utils.UnwrapError(serr) + return serr } threadID = "" // unknown event edge case - remove existing thread ID to avoid complications newThread = true @@ -238,7 +239,7 @@ func (b *Bot) sendAutoreply(roomID id.RoomID, threadID id.EventID) { } if err != nil { - b.Error(ctx, evt.RoomID, "cannot send email: %v", err) + b.Error(ctx, "cannot send email: %v", err) continue } } @@ -260,12 +261,12 @@ func (b *Bot) SendEmailReply(ctx context.Context) { } cfg, err := b.cfg.GetRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot retrieve room settings: %v", err) + b.Error(ctx, "cannot retrieve room settings: %v", err) return } mailbox := cfg.Mailbox() if mailbox == "" { - b.Error(ctx, evt.RoomID, "mailbox is not configured, kupo") + b.Error(ctx, "mailbox is not configured, kupo") return } @@ -275,7 +276,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) { meta := b.getParentEmail(evt, mailbox) if meta.To == "" { - b.Error(ctx, evt.RoomID, "cannot find parent email and continue the thread. Please, start a new email thread") + b.Error(ctx, "cannot find parent email and continue the thread. Please, start a new email thread") return } @@ -305,7 +306,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) { eml := email.New(meta.MessageID, meta.InReplyTo, meta.References, meta.Subject, meta.From, meta.To, meta.RcptTo, meta.CC, body, htmlBody, nil, nil) data := eml.Compose(b.cfg.GetBot().DKIMPrivateKey()) if data == "" { - b.SendError(ctx, evt.RoomID, "email body is empty") + b.lp.SendNotice(evt.RoomID, "email body is empty", utils.RelatesTo(!cfg.NoThreads(), evt.ID)) return } @@ -320,7 +321,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) { } if err != nil { - b.Error(ctx, evt.RoomID, "cannot send email: %v", err) + b.Error(ctx, "cannot send email: %v", err) continue } } @@ -419,7 +420,7 @@ func (e *parentEmail) calculateRecipients(from string, forwardedFrom []string) { func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) { content := evt.Content.AsMessage() - threadID := utils.EventParent(evt.ID, content) + threadID := linkpearl.EventParent(evt.ID, content) b.log.Debug().Str("eventID", evt.ID.String()).Str("threadID", threadID.String()).Msg("looking up for the parent event within thread") if threadID == evt.ID { b.log.Debug().Str("eventID", evt.ID.String()).Msg("event is the thread itself") @@ -435,7 +436,7 @@ func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) { b.log.Error().Err(err).Msg("cannot get parent event") return threadID, nil } - utils.ParseContent(parentEvt, parentEvt.Type) + linkpearl.ParseContent(parentEvt, parentEvt.Type, b.log) if !b.lp.GetMachine().StateStore.IsEncrypted(evt.RoomID) { return threadID, parentEvt @@ -461,12 +462,12 @@ func (b *Bot) getParentEmail(evt *event.Event, newFromMailbox string) *parentEma return parent } - parent.From = utils.EventField[string](&parentEvt.Content, eventFromKey) - parent.To = utils.EventField[string](&parentEvt.Content, eventToKey) - parent.CC = utils.EventField[string](&parentEvt.Content, eventCcKey) - parent.RcptTo = utils.EventField[string](&parentEvt.Content, eventRcptToKey) - parent.InReplyTo = utils.EventField[string](&parentEvt.Content, eventMessageIDkey) - parent.References = utils.EventField[string](&parentEvt.Content, eventReferencesKey) + parent.From = linkpearl.EventField[string](&parentEvt.Content, eventFromKey) + parent.To = linkpearl.EventField[string](&parentEvt.Content, eventToKey) + parent.CC = linkpearl.EventField[string](&parentEvt.Content, eventCcKey) + parent.RcptTo = linkpearl.EventField[string](&parentEvt.Content, eventRcptToKey) + parent.InReplyTo = linkpearl.EventField[string](&parentEvt.Content, eventMessageIDkey) + parent.References = linkpearl.EventField[string](&parentEvt.Content, eventReferencesKey) senderEmail := parent.fixtofrom(newFromMailbox, b.domains) parent.calculateRecipients(senderEmail, b.mbxc.Forwarded) parent.MessageID = email.MessageID(parentEvt.ID, parent.FromDomain) @@ -477,7 +478,7 @@ func (b *Bot) getParentEmail(evt *event.Event, newFromMailbox string) *parentEma parent.References = " " + parent.MessageID } - parent.Subject = utils.EventField[string](&parentEvt.Content, eventSubjectKey) + parent.Subject = linkpearl.EventField[string](&parentEvt.Content, eventSubjectKey) if parent.Subject != "" { parent.Subject = "Re: " + parent.Subject } else { @@ -504,16 +505,17 @@ func (b *Bot) saveSentMetadata(ctx context.Context, queued bool, threadID id.Eve notice := format.RenderMarkdown(text, true, true) msgContent, ok := content.Parsed.(*event.MessageEventContent) if !ok { - b.Error(ctx, evt.RoomID, "cannot parse message") + b.Error(ctx, "cannot parse message") return } msgContent.MsgType = event.MsgNotice msgContent.Body = notice.Body msgContent.FormattedBody = notice.FormattedBody + msgContent.RelatesTo = utils.RelatesTo(!cfg.NoThreads(), evt.ID) content.Parsed = msgContent msgID, err := b.lp.Send(evt.RoomID, content) if err != nil { - b.Error(ctx, evt.RoomID, "cannot send notice: %v", err) + b.Error(ctx, "cannot send notice: %v", err) return } domain := utils.SanitizeDomain(cfg.Domain()) @@ -527,7 +529,7 @@ func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.Fi req := file.Convert() err := b.lp.SendFile(roomID, req, file.MsgType, utils.RelatesTo(!noThreads, parentID)) if err != nil { - b.Error(ctx, roomID, "cannot upload file %s: %v", req.FileName, err) + b.Error(ctx, "cannot upload file %s: %v", req.FileName, err) } } } diff --git a/bot/reaction.go b/bot/reaction.go index 0599488..0bf131c 100644 --- a/bot/reaction.go +++ b/bot/reaction.go @@ -3,9 +3,8 @@ package bot import ( "context" + "gitlab.com/etke.cc/linkpearl" "maunium.net/go/mautrix/event" - - "gitlab.com/etke.cc/postmoogle/utils" ) var supportedReactions = map[string]string{ @@ -26,18 +25,18 @@ func (b *Bot) handleReaction(ctx context.Context) { srcID := content.GetRelatesTo().EventID srcEvt, err := b.lp.GetClient().GetEvent(evt.RoomID, srcID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot find event %s: %v", srcID, err) + b.Error(ctx, "cannot find event %s: %v", srcID, err) return } - utils.ParseContent(evt, event.EventMessage) + linkpearl.ParseContent(evt, event.EventMessage, b.log) switch action { case commandSpamlistAdd: - sender := utils.EventField[string](&srcEvt.Content, eventFromKey) + sender := linkpearl.EventField[string](&srcEvt.Content, eventFromKey) if sender == "" { - b.Error(ctx, evt.RoomID, "cannot get sender of the email") + b.Error(ctx, "cannot get sender of the email") return } - b.runSpamlistAdd(ctx, []string{commandSpamlistAdd, utils.EventField[string](&srcEvt.Content, eventFromKey)}) + b.runSpamlistAdd(ctx, []string{commandSpamlistAdd, linkpearl.EventField[string](&srcEvt.Content, eventFromKey)}) } } diff --git a/bot/sync.go b/bot/sync.go index a1ef8cf..91cee1b 100644 --- a/bot/sync.go +++ b/bot/sync.go @@ -101,7 +101,7 @@ func (b *Bot) onBotJoin(ctx context.Context) { return } - b.sendIntroduction(ctx, evt.RoomID) + b.sendIntroduction(evt.RoomID) b.sendHelp(ctx) } @@ -124,7 +124,7 @@ func (b *Bot) onLeave(ctx context.Context) { b.runStop(ctx) _, err := b.lp.GetClient().LeaveRoom(evt.RoomID) if err != nil { - b.Error(ctx, evt.RoomID, "cannot leave empty room: %v", err) + b.Error(ctx, "cannot leave empty room: %v", err) } } } diff --git a/cmd/cmd.go b/cmd/cmd.go index b3b5565..ddf2b10 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -41,7 +41,6 @@ func main() { cfg := config.New() initLog(cfg) - utils.SetLogger(&log) utils.SetDomains(cfg.Domains) log.Info().Msg("#############################") diff --git a/go.mod b/go.mod index 54c6077..55047bc 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( gitlab.com/etke.cc/go/secgen v1.1.1 gitlab.com/etke.cc/go/trysmtp v1.1.3 gitlab.com/etke.cc/go/validator v1.0.6 - gitlab.com/etke.cc/linkpearl v0.0.0-20230920071429-25fe33ba08d0 + gitlab.com/etke.cc/linkpearl v0.0.0-20230927084751-e9a37b134a8a golang.org/x/exp v0.0.0-20230905200255-921286631fa9 maunium.net/go/mautrix v0.16.1 ) diff --git a/go.sum b/go.sum index d0b4bda..63b3c33 100644 --- a/go.sum +++ b/go.sum @@ -111,8 +111,8 @@ gitlab.com/etke.cc/go/trysmtp v1.1.3 h1:e2EHond77onMaecqCg6mWumffTSEf+ycgj88nbee gitlab.com/etke.cc/go/trysmtp v1.1.3/go.mod h1:lOO7tTdAE0a3ETV3wN3GJ7I1Tqewu7YTpPWaOmTteV0= gitlab.com/etke.cc/go/validator v1.0.6 h1:w0Muxf9Pqw7xvF7NaaswE6d7r9U3nB2t2l5PnFMrecQ= gitlab.com/etke.cc/go/validator v1.0.6/go.mod h1:Id0SxRj0J3IPhiKlj0w1plxVLZfHlkwipn7HfRZsDts= -gitlab.com/etke.cc/linkpearl v0.0.0-20230920071429-25fe33ba08d0 h1:7fx8afCUluCzJISPUr6j8przpwdcCCXqqPHWvPRmzhA= -gitlab.com/etke.cc/linkpearl v0.0.0-20230920071429-25fe33ba08d0/go.mod h1:IZ0TE+ZnIdJLb538owDMxhtpWH7blfW+oR7e5XRXxNY= +gitlab.com/etke.cc/linkpearl v0.0.0-20230927084751-e9a37b134a8a h1:DRSWdLpi1s9MLlXCbrQ6ymJJCqQYemi2wFZP3u9ROb8= +gitlab.com/etke.cc/linkpearl v0.0.0-20230927084751-e9a37b134a8a/go.mod h1:IZ0TE+ZnIdJLb538owDMxhtpWH7blfW+oR7e5XRXxNY= go.mau.fi/util v0.1.0 h1:BwIFWIOEeO7lsiI2eWKFkWTfc5yQmoe+0FYyOFVyaoE= go.mau.fi/util v0.1.0/go.mod h1:AxuJUMCxpzgJ5eV9JbPWKRH8aAJJidxetNdUj7qcb84= golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= diff --git a/utils/matrix.go b/utils/matrix.go index 0b24e14..0dd9950 100644 --- a/utils/matrix.go +++ b/utils/matrix.go @@ -1,7 +1,6 @@ package utils import ( - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" ) @@ -25,79 +24,3 @@ func RelatesTo(threads bool, parentID id.EventID) *event.RelatesTo { }, } } - -// EventParent returns parent event ID (either from thread or from reply-to relation) -func EventParent(currentID id.EventID, content *event.MessageEventContent) id.EventID { - if content == nil { - return currentID - } - - relation := content.OptionalGetRelatesTo() - if relation == nil { - return currentID - } - - threadParent := relation.GetThreadParent() - if threadParent != "" { - return threadParent - } - - replyParent := relation.GetReplyTo() - if replyParent != "" { - return replyParent - } - - return currentID -} - -// EventField returns field value from raw event content -func EventField[T any](content *event.Content, field string) T { - var zero T - raw := content.Raw[field] - if raw == nil { - return zero - } - - v, ok := raw.(T) - if !ok { - return zero - } - - return v -} - -func ParseContent(evt *event.Event, eventType event.Type) { - if evt.Content.Parsed != nil { - return - } - perr := evt.Content.ParseRaw(eventType) - if perr != nil { - log.Error().Err(perr).Msg("cannot parse event content") - } -} - -// UnwrapError tries to unwrap a error into something meaningful, like mautrix.HTTPError or mautrix.RespError -func UnwrapError(err error) error { - switch err.(type) { - case nil: - return nil - case mautrix.HTTPError: - return unwrapHTTPError(err) - default: - return err - } -} - -func unwrapHTTPError(err error) error { - httperr, ok := err.(mautrix.HTTPError) - if !ok { - return err - } - - uwerr := httperr.Unwrap() - if uwerr != nil { - return uwerr - } - - return httperr -} diff --git a/utils/utils.go b/utils/utils.go index b60de8a..bef0742 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -5,19 +5,9 @@ import ( "sort" "strconv" "strings" - - "github.com/rs/zerolog" ) -var ( - log *zerolog.Logger - domains []string -) - -// SetLogger for utils -func SetLogger(loggerInstance *zerolog.Logger) { - log = loggerInstance -} +var domains []string // SetDomains for later use func SetDomains(slice []string) { diff --git a/vendor/gitlab.com/etke.cc/linkpearl/accountdata.go b/vendor/gitlab.com/etke.cc/linkpearl/accountdata.go index bbf1610..c438c47 100644 --- a/vendor/gitlab.com/etke.cc/linkpearl/accountdata.go +++ b/vendor/gitlab.com/etke.cc/linkpearl/accountdata.go @@ -24,7 +24,7 @@ func (l *Linkpearl) GetAccountData(name string) (map[string]string, error) { l.acc.Add(name, data) return data, nil } - return data, err + return data, UnwrapError(err) } data = l.decryptAccountData(data) @@ -37,7 +37,7 @@ func (l *Linkpearl) SetAccountData(name string, data map[string]string) error { l.acc.Add(name, data) data = l.encryptAccountData(data) - return l.GetClient().SetAccountData(name, data) + return UnwrapError(l.GetClient().SetAccountData(name, data)) } // GetRoomAccountData of the room (from cache and API, with encryption support) @@ -59,7 +59,7 @@ func (l *Linkpearl) GetRoomAccountData(roomID id.RoomID, name string) (map[strin l.acc.Add(key, data) return data, nil } - return data, err + return data, UnwrapError(err) } data = l.decryptAccountData(data) @@ -73,7 +73,7 @@ func (l *Linkpearl) SetRoomAccountData(roomID id.RoomID, name string, data map[s l.acc.Add(key, data) data = l.encryptAccountData(data) - return l.GetClient().SetRoomAccountData(roomID, name, data) + return UnwrapError(l.GetClient().SetRoomAccountData(roomID, name, data)) } func (l *Linkpearl) encryptAccountData(data map[string]string) map[string]string { diff --git a/vendor/gitlab.com/etke.cc/linkpearl/send.go b/vendor/gitlab.com/etke.cc/linkpearl/send.go index 099f38b..fd75a3a 100644 --- a/vendor/gitlab.com/etke.cc/linkpearl/send.go +++ b/vendor/gitlab.com/etke.cc/linkpearl/send.go @@ -1,8 +1,6 @@ package linkpearl import ( - "fmt" - "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format" @@ -16,24 +14,22 @@ func (l *Linkpearl) Send(roomID id.RoomID, content interface{}) (id.EventID, err l.log.Debug().Str("roomID", roomID.String()).Any("content", content).Msg("sending event") resp, err := l.api.SendMessageEvent(roomID, event.EventMessage, content) if err != nil { - return "", err + return "", UnwrapError(err) } return resp.EventID, nil } -// SendNotice to a room with optional thread relation -func (l *Linkpearl) SendNotice(roomID id.RoomID, threadID id.EventID, message string, args ...interface{}) { - content := format.RenderMarkdown(fmt.Sprintf(message, args...), true, true) - if threadID != "" { - content.RelatesTo = &event.RelatesTo{ - Type: event.RelThread, - EventID: threadID, - } +// SendNotice to a room with optional relations, markdown supported +func (l *Linkpearl) SendNotice(roomID id.RoomID, message string, relates ...*event.RelatesTo) { + content := format.RenderMarkdown(message, true, true) + content.MsgType = event.MsgNotice + if len(relates) > 0 { + content.RelatesTo = relates[0] } _, err := l.Send(roomID, &content) if err != nil { - l.log.Error().Err(err).Str("roomID", roomID.String()).Msg("cannot send a notice int the room") + l.log.Error().Err(UnwrapError(err)).Str("roomID", roomID.String()).Msg("cannot send a notice int the room") } } @@ -41,6 +37,7 @@ func (l *Linkpearl) SendNotice(roomID id.RoomID, threadID id.EventID, message st func (l *Linkpearl) SendFile(roomID id.RoomID, req *mautrix.ReqUploadMedia, msgtype event.MessageType, relation *event.RelatesTo) error { resp, err := l.GetClient().UploadMedia(*req) if err != nil { + err = UnwrapError(err) l.log.Error().Err(err).Str("file", req.FileName).Msg("cannot upload file") return err } @@ -52,6 +49,7 @@ func (l *Linkpearl) SendFile(roomID id.RoomID, req *mautrix.ReqUploadMedia, msgt RelatesTo: relation, }, }) + err = UnwrapError(err) if err != nil { l.log.Error().Err(err).Str("file", req.FileName).Msg("cannot send uploaded file") } diff --git a/vendor/gitlab.com/etke.cc/linkpearl/utils.go b/vendor/gitlab.com/etke.cc/linkpearl/utils.go new file mode 100644 index 0000000..acecf2b --- /dev/null +++ b/vendor/gitlab.com/etke.cc/linkpearl/utils.go @@ -0,0 +1,84 @@ +package linkpearl + +import ( + "github.com/rs/zerolog" + "maunium.net/go/mautrix" + "maunium.net/go/mautrix/event" + "maunium.net/go/mautrix/id" +) + +// EventParent returns parent event ID (either from thread or from reply-to relation) +func EventParent(currentID id.EventID, content *event.MessageEventContent) id.EventID { + if content == nil { + return currentID + } + + relation := content.OptionalGetRelatesTo() + if relation == nil { + return currentID + } + + threadParent := relation.GetThreadParent() + if threadParent != "" { + return threadParent + } + + replyParent := relation.GetReplyTo() + if replyParent != "" { + return replyParent + } + + return currentID +} + +// EventField returns field value from raw event content +func EventField[T any](content *event.Content, field string) T { + var zero T + raw := content.Raw[field] + if raw == nil { + return zero + } + + v, ok := raw.(T) + if !ok { + return zero + } + + return v +} + +func ParseContent(evt *event.Event, eventType event.Type, log *zerolog.Logger) { + if evt.Content.Parsed != nil { + return + } + perr := evt.Content.ParseRaw(eventType) + if perr != nil { + log.Error().Err(perr).Msg("cannot parse event content") + } +} + +// UnwrapError tries to unwrap a error into something meaningful, like mautrix.HTTPError or mautrix.RespError +func UnwrapError(err error) error { + switch err.(type) { + case nil: + return nil + case mautrix.HTTPError: + return unwrapHTTPError(err) + default: + return err + } +} + +func unwrapHTTPError(err error) error { + httperr, ok := err.(mautrix.HTTPError) + if !ok { + return err + } + + uwerr := httperr.Unwrap() + if uwerr != nil { + return uwerr + } + + return httperr +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 69f772d..8e2903f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -144,7 +144,7 @@ gitlab.com/etke.cc/go/trysmtp # gitlab.com/etke.cc/go/validator v1.0.6 ## explicit; go 1.18 gitlab.com/etke.cc/go/validator -# gitlab.com/etke.cc/linkpearl v0.0.0-20230920071429-25fe33ba08d0 +# gitlab.com/etke.cc/linkpearl v0.0.0-20230927084751-e9a37b134a8a ## explicit; go 1.18 gitlab.com/etke.cc/linkpearl # go.mau.fi/util v0.1.0