add '!pm aliases' command

This commit is contained in:
Aine 2024-08-18 14:55:24 +03:00
parent bd81c93b63
commit f23929b631
No known key found for this signature in database
GPG key ID: 34969C908CCA2804
6 changed files with 82 additions and 8 deletions

View file

@ -19,6 +19,7 @@ so you can use it to send emails from your apps and scripts as well.
- [x] Receive emails to matrix rooms - [x] Receive emails to matrix rooms
- [x] Receive attachments - [x] Receive attachments
- [x] Subaddressing support - [x] Subaddressing support
- [x] Mailbox aliases support
- [x] Catch-all mailbox - [x] Catch-all mailbox
- [x] Strip forwarding, signatures, and other noise from emails if configured - [x] Strip forwarding, signatures, and other noise from emails if configured
- [x] Map email threads to matrix threads - [x] Map email threads to matrix threads
@ -117,6 +118,7 @@ If you want to change them - check available options in the help message (`!pm h
> The following section is visible to the mailbox owners only > The following section is visible to the mailbox owners only
* **`!pm mailbox`** - Get or set mailbox of the room * **`!pm mailbox`** - Get or set mailbox of the room
* **`!pm aliases`** - Get or set comma-separated aliases of the room
* **`!pm domain`** - Get or set default domain of the room * **`!pm domain`** - Get or set default domain of the room
* **`!pm owner`** - Get or set owner of the room * **`!pm owner`** - Get or set owner of the room
* **`!pm password`** - Get or set SMTP password of the room's mailbox * **`!pm password`** - Get or set SMTP password of the room's mailbox

View file

@ -8,7 +8,7 @@ import (
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
) )
type activationFlow func(context.Context, id.UserID, id.RoomID, string) bool type activationFlow func(context.Context, id.UserID, id.RoomID, string, bool) bool
func (b *Bot) getActivationFlow() activationFlow { func (b *Bot) getActivationFlow() activationFlow {
switch b.mbxc.Activation { switch b.mbxc.Activation {
@ -24,17 +24,22 @@ func (b *Bot) getActivationFlow() activationFlow {
// ActivateMailbox using the configured flow // ActivateMailbox using the configured flow
func (b *Bot) ActivateMailbox(ctx context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string) bool { func (b *Bot) ActivateMailbox(ctx context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string) bool {
flow := b.getActivationFlow() flow := b.getActivationFlow()
return flow(ctx, ownerID, roomID, mailbox) return flow(ctx, ownerID, roomID, mailbox, false)
} }
func (b *Bot) activateNone(_ context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string) bool { func (b *Bot) ActivateAlias(ctx context.Context, ownerID id.UserID, roomID id.RoomID, alias string) bool {
flow := b.getActivationFlow()
return flow(ctx, ownerID, roomID, alias, true)
}
func (b *Bot) activateNone(_ context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string, _ bool) bool {
b.log.Debug().Str("mailbox", mailbox).Str("roomID", roomID.String()).Str("ownerID", ownerID.String()).Msg("activating mailbox through the flow 'none'") b.log.Debug().Str("mailbox", mailbox).Str("roomID", roomID.String()).Str("ownerID", ownerID.String()).Msg("activating mailbox through the flow 'none'")
b.rooms.Store(mailbox, roomID) b.rooms.Store(mailbox, roomID)
return true return true
} }
func (b *Bot) activateNotify(ctx context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string) bool { func (b *Bot) activateNotify(ctx context.Context, ownerID id.UserID, roomID id.RoomID, mailbox string, alias bool) bool {
b.log.Debug().Str("mailbox", mailbox).Str("roomID", roomID.String()).Str("ownerID", ownerID.String()).Msg("activating mailbox through the flow 'notify'") b.log.Debug().Str("mailbox", mailbox).Str("roomID", roomID.String()).Str("ownerID", ownerID.String()).Msg("activating mailbox through the flow 'notify'")
b.rooms.Store(mailbox, roomID) b.rooms.Store(mailbox, roomID)
if len(b.adminRooms) == 0 { if len(b.adminRooms) == 0 {
@ -42,6 +47,9 @@ func (b *Bot) activateNotify(ctx context.Context, ownerID id.UserID, roomID id.R
} }
msg := fmt.Sprintf("Mailbox %q has been registered by %q for the room %q", mailbox, ownerID, roomID) msg := fmt.Sprintf("Mailbox %q has been registered by %q for the room %q", mailbox, ownerID, roomID)
if alias {
msg = fmt.Sprintf("Alias %q has been registered by %q for the room %q", mailbox, ownerID, roomID)
}
for _, adminRoom := range b.adminRooms { for _, adminRoom := range b.adminRooms {
content := format.RenderMarkdown(msg, true, true) content := format.RenderMarkdown(msg, true, true)
_, err := b.lp.Send(ctx, adminRoom, &content) _, err := b.lp.Send(ctx, adminRoom, &content)

View file

@ -26,6 +26,7 @@ const (
commandUsers = config.BotUsers commandUsers = config.BotUsers
commandQueueBatch = config.BotQueueBatch commandQueueBatch = config.BotQueueBatch
commandQueueRetries = config.BotQueueRetries commandQueueRetries = config.BotQueueRetries
commandAliasesRemove = "aliases:remove"
commandSpamlist = "spam:list" commandSpamlist = "spam:list"
commandSpamlistAdd = "spam:add" commandSpamlistAdd = "spam:add"
commandSpamlistRemove = "spam:remove" commandSpamlistRemove = "spam:remove"
@ -86,6 +87,12 @@ func (b *Bot) initCommands() commandList {
sanitizer: utils.Mailbox, sanitizer: utils.Mailbox,
allowed: b.allowOwner, allowed: b.allowOwner,
}, },
{
key: config.RoomAliases,
description: "Show/edit comma-separated aliases of the room",
sanitizer: utils.SanitizeStringSlice,
allowed: b.allowOwner,
},
{ {
key: config.RoomDomain, key: config.RoomDomain,
description: "Get or set default domain of the room", description: "Get or set default domain of the room",

View file

@ -49,6 +49,8 @@ func (b *Bot) handleOption(ctx context.Context, cmd []string) {
return return
case config.RoomMailbox: case config.RoomMailbox:
b.setMailbox(ctx, cmd[1]) b.setMailbox(ctx, cmd[1])
case config.RoomAliases:
b.setAliases(ctx, cmd[1])
case config.RoomPassword: case config.RoomPassword:
b.setPassword(ctx) b.setPassword(ctx)
case config.RoomRelay: case config.RoomRelay:
@ -129,6 +131,48 @@ func (b *Bot) setMailbox(ctx context.Context, value string) {
b.lp.SendNotice(ctx, evt.RoomID, msg, linkpearl.RelatesTo(evt.ID, cfg.NoThreads())) b.lp.SendNotice(ctx, evt.RoomID, msg, linkpearl.RelatesTo(evt.ID, cfg.NoThreads()))
} }
func (b *Bot) setAliases(ctx context.Context, value string) {
evt := eventFromContext(ctx)
aliases := strings.Split(value, ",")
for _, alias := range aliases {
existingID, ok := b.getMapping(alias)
if (ok && existingID != "" && existingID != evt.RoomID) || b.isReserved(alias) {
b.lp.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Mailbox `%s` (%s) already taken, kupo", value, utils.EmailsList(value, "")))
return
}
}
cfg, err := b.cfg.GetRoom(ctx, evt.RoomID)
if err != nil {
b.Error(ctx, "failed to retrieve settings: %v", err)
return
}
old := cfg.Get(config.RoomAliases)
oldAliases := utils.StringSlice(old)
cfg.Set(config.RoomAliases, value)
cfg.Set(config.RoomOwner, evt.Sender.String())
if old != "" {
b.rooms.Delete(old)
}
valueParts := make([]string, 0, len(aliases))
for _, alias := range aliases {
if !slices.Contains(oldAliases, alias) {
b.ActivateAlias(ctx, evt.Sender, evt.RoomID, value)
}
valueParts = append(valueParts, fmt.Sprintf("%s@%s", alias, utils.SanitizeDomain(cfg.Domain())))
}
value = utils.SliceString(valueParts)
err = b.cfg.SetRoom(ctx, evt.RoomID, cfg)
if err != nil {
b.Error(ctx, "cannot update settings: %v", err)
return
}
msg := fmt.Sprintf("aliases of this room set to `%s`", value)
b.lp.SendNotice(ctx, evt.RoomID, msg, linkpearl.RelatesTo(evt.ID, cfg.NoThreads()))
}
func (b *Bot) setPassword(ctx context.Context) { func (b *Bot) setPassword(ctx context.Context) {
evt := eventFromContext(ctx) evt := eventFromContext(ctx)
cfg, err := b.cfg.GetRoom(ctx, evt.RoomID) cfg, err := b.cfg.GetRoom(ctx, evt.RoomID)

View file

@ -20,6 +20,7 @@ const (
RoomActive = ".active" RoomActive = ".active"
RoomOwner = "owner" RoomOwner = "owner"
RoomMailbox = "mailbox" RoomMailbox = "mailbox"
RoomAliases = "aliases"
RoomDomain = "domain" RoomDomain = "domain"
RoomPassword = "password" RoomPassword = "password"
RoomSignature = "signature" RoomSignature = "signature"
@ -62,6 +63,10 @@ func (s Room) Mailbox() string {
return s.Get(RoomMailbox) return s.Get(RoomMailbox)
} }
func (s Room) Aliases() []string {
return utils.StringSlice(s.Get(RoomAliases))
}
func (s Room) Domain() string { func (s Room) Domain() string {
return s.Get(RoomDomain) return s.Get(RoomDomain)
} }

View file

@ -10,6 +10,16 @@ import (
"gitlab.com/etke.cc/postmoogle/bot/config" "gitlab.com/etke.cc/postmoogle/bot/config"
) )
func (b *Bot) addRoom(roomID id.RoomID, cfg config.Room) {
b.rooms.Store(cfg.Mailbox(), roomID)
aliases := cfg.Aliases()
if len(aliases) > 0 {
for _, alias := range aliases {
b.rooms.Store(alias, roomID)
}
}
}
func (b *Bot) syncRooms(ctx context.Context) error { func (b *Bot) syncRooms(ctx context.Context) error {
adminRooms := []id.RoomID{} adminRooms := []id.RoomID{}
@ -28,10 +38,8 @@ func (b *Bot) syncRooms(ctx context.Context) error {
if serr != nil { if serr != nil {
continue continue
} }
mailbox := cfg.Mailbox() if cfg.Mailbox() != "" && cfg.Active() {
active := cfg.Active() b.addRoom(roomID, cfg)
if mailbox != "" && active {
b.rooms.Store(mailbox, roomID)
} }
if cfg.Owner() != "" && b.allowAdmin(ctx, id.UserID(cfg.Owner()), "") { if cfg.Owner() != "" && b.allowAdmin(ctx, id.UserID(cfg.Owner()), "") {