carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3import (
4 "context"
5 "errors"
6 "log"
7 "strings"
8 "time"
9)
10
11// deliveryChannel names how deliver got a message out.
12type deliveryChannel string
13
14const (
15 deliveredKeymail deliveryChannel = "keymail"
16 deliveredEmail deliveryChannel = "email"
17)
18
19// domainOf is the lowercased part of addr after its last "@", "" if none.
20func domainOf(addr string) string {
21 i := strings.LastIndex(addr, "@")
22 if i < 0 {
23 return ""
24 }
25 return strings.ToLower(addr[i+1:])
26}
27
28// deliver sends one message to an address the person did not just type (an
29// invite, a notice): Keymail federation first, then the console mailer (SES).
30// The fall-through rule (spec 4.3):
31//
32// - a definite "no mailbox" (ErrNoKeymailMailbox) goes to the mailer;
33// - an unreachable lookup stops when the address is at the Keymail host
34// (it IS a Keymail mailbox, so SES must not be used), and otherwise goes
35// to the mailer;
36// - a block, a price above the cap, or any failure after a successful
37// lookup stops with that error: the address is a Keymail mailbox.
38//
39// keymailShare bounds Keymail's part of ctx so the mailer keeps the rest.
40// On error the channel is "".
41func (s *Server) deliver(ctx context.Context, to, subject, body string, keymailShare time.Duration) (deliveryChannel, error) {
42 if s.sendFederated != nil {
43 kctx, cancel := context.WithTimeout(ctx, keymailShare)
44 _, err := s.sendFederated(kctx, to, subject, body)
45 cancel()
46 if err == nil {
47 return deliveredKeymail, nil
48 }
49 switch {
50 case IsKeymailBlocked(err):
51 // The recipient blocked the console. That is their answer;
52 // email to the same address would go round it.
53 log.Printf("console: delivery to %s: the recipient blocked the console on keymail; not emailing", to)
54 return "", err
55 case errors.Is(err, ErrNoKeymailMailbox):
56 log.Printf("console: delivery to %s: no keymail mailbox, trying email", to)
57 case errors.Is(err, ErrKeymailUnreachable):
58 if s.km != nil && domainOf(to) == s.km.Host() {
59 log.Printf("console: delivery to %s: keymail lookup unreachable for a keymail address; not emailing: %v", to, err)
60 return "", err
61 }
62 log.Printf("console: delivery to %s: keymail lookup unreachable, trying email: %v", to, err)
63 default:
64 // ErrFederationPriceTooHigh, or a failure after the lookup
65 // said the mailbox exists.
66 log.Printf("console: delivery to %s by keymail: %v", to, err)
67 return "", err
68 }
69 }
70 if s.consoleMail == nil {
71 return "", errors.New("console: no email sender is configured")
72 }
73 if err := s.consoleMail.Send(ctx, to, subject, body); err != nil {
74 log.Printf("console: delivery to %s by email: %v", to, err)
75 return "", err
76 }
77 return deliveredEmail, nil
78}
79