diff options
author | Simon Ser <contact@emersion.fr> | 2020-01-10 19:37:56 +0100 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2020-02-05 12:21:54 +0100 |
commit | 6a6ece03e49f29de32c8e6d598871de764e07232 (patch) | |
tree | 6e1208ce6da995ffbd02593d7be230e5d1c54d7b /plugins/carddav | |
parent | 6ea7cd9134318874a21aa08ea0d9feecadd8874d (diff) | |
download | alps-6a6ece03e49f29de32c8e6d598871de764e07232.tar.gz alps-6a6ece03e49f29de32c8e6d598871de764e07232.zip |
plugins/carddav: new plugin
A new minimal CardDAV plugin is introduced. It injects a list of e-mail
addresses in the e-mail compose view.
References: https://todo.sr.ht/~sircmpwn/koushin/7
Diffstat (limited to 'plugins/carddav')
-rw-r--r-- | plugins/carddav/plugin.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/plugins/carddav/plugin.go b/plugins/carddav/plugin.go new file mode 100644 index 0000000..45e447e --- /dev/null +++ b/plugins/carddav/plugin.go @@ -0,0 +1,116 @@ +package koushincarddav + +import ( + "fmt" + "net/http" + "net/url" + + "git.sr.ht/~emersion/koushin" + koushinbase "git.sr.ht/~emersion/koushin/plugins/base" + "github.com/emersion/go-vcard" + "github.com/emersion/go-webdav/carddav" +) + +type authRoundTripper struct { + upstream http.RoundTripper + session *koushin.Session +} + +func (rt *authRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + rt.session.SetHTTPBasicAuth(req) + return rt.upstream.RoundTrip(req) +} + +func newPlugin(srv *koushin.Server) (koushin.Plugin, error) { + u, err := srv.Upstream("https", "http+insecure") + if _, ok := err.(*koushin.NoUpstreamError); ok { + srv.Logger().Print("carddav: no upstream server provided") + return nil, nil + } else if err != nil { + return nil, fmt.Errorf("carddav: failed to parse upstream CardDAV server: %v", err) + } + if u.Scheme == "http+insecure" { + u.Scheme = "http" + } + if u.Scheme == "" { + s, err := carddav.Discover(u.Host) + if err != nil { + srv.Logger().Printf("carddav: failed to discover CardDAV server: %v", err) + return nil, nil + } + u, err = url.Parse(s) + if err != nil { + return nil, fmt.Errorf("carddav: Discover returned an invalid URL: %v", err) + } + } + srv.Logger().Printf("Configured upstream CardDAV server: %v", u) + + p := koushin.GoPlugin{Name: "carddav"} + + p.Inject("compose.html", func(ctx *koushin.Context, _data koushin.RenderData) error { + data := _data.(*koushinbase.ComposeRenderData) + + rt := authRoundTripper{ + upstream: http.DefaultTransport, + session: ctx.Session, + } + c, err := carddav.NewClient(&http.Client{Transport: &rt}, u.String()) + if err != nil { + return fmt.Errorf("failed to create CardDAV client: %v", err) + } + + principal, err := c.FindCurrentUserPrincipal() + if err != nil { + return fmt.Errorf("failed to query CardDAV principal: %v", err) + } + + addressBookHomeSet, err := c.FindAddressBookHomeSet(principal) + if err != nil { + return fmt.Errorf("failed to query CardDAV address book home set: %v", err) + } + + addressBooks, err := c.FindAddressBooks(addressBookHomeSet) + if err != nil { + return fmt.Errorf("failed to query CardDAV address books: %v", err) + } + if len(addressBooks) == 0 { + return nil + } + addressBook := addressBooks[0] + + query := carddav.AddressBookQuery{ + DataRequest: carddav.AddressDataRequest{ + Props: []string{vcard.FieldFormattedName, vcard.FieldEmail}, + }, + } + addrs, err := c.QueryAddressBook(addressBook.Path, &query) + if err != nil { + return fmt.Errorf("failed to query CardDAV addresses: %v", err) + } + + // TODO: cache the results + emails := make([]string, 0, len(addrs)) + for _, addr := range addrs { + cardEmails := addr.Card.Values(vcard.FieldEmail) + emails = append(emails, cardEmails...) + } + + data.Extra["EmailSuggestions"] = emails + return nil + }) + + return p.Plugin(), nil +} + +func init() { + koushin.RegisterPluginLoader(func(s *koushin.Server) ([]koushin.Plugin, error) { + p, err := newPlugin(s) + if err != nil { + return nil, err + } + if p == nil { + return nil, nil + } + return []koushin.Plugin{p}, err + }) +} |