ref: 67fb0938a66605a0b6a837005804637b348b250d aerc/commands/msg/unsubscribe.go -rw-r--r-- 2.7 KiB View raw
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package msg

import (
	"bufio"
	"errors"
	"net/url"
	"strings"

	"git.sr.ht/~sircmpwn/aerc/lib"
	"git.sr.ht/~sircmpwn/aerc/widgets"
)

// Unsubscribe helps people unsubscribe from mailing lists by way of the
// List-Unsubscribe header.
type Unsubscribe struct{}

func init() {
	register(Unsubscribe{})
}

// Aliases returns a list of aliases for the :unsubscribe command
func (Unsubscribe) Aliases() []string {
	return []string{"unsubscribe"}
}

// Complete returns a list of completions
func (Unsubscribe) Complete(aerc *widgets.Aerc, args []string) []string {
	return nil
}

// Execute runs the Unsubscribe command
func (Unsubscribe) Execute(aerc *widgets.Aerc, args []string) error {
	if len(args) != 1 {
		return errors.New("Usage: unsubscribe")
	}
	widget := aerc.SelectedTab().(widgets.ProvidesMessage)
	msg, err := widget.SelectedMessage()
	if err != nil {
		return err
	}
	headers := msg.RFC822Headers
	if !headers.Has("list-unsubscribe") {
		return errors.New("No List-Unsubscribe header found")
	}
	methods := parseUnsubscribeMethods(headers.Get("list-unsubscribe"))
	aerc.Logger().Printf("found %d unsubscribe methods", len(methods))
	for _, method := range methods {
		aerc.Logger().Printf("trying to unsubscribe using %v", method)
		switch method.Scheme {
		case "mailto":
			return unsubscribeMailto(aerc, method)
		case "http", "https":
			return unsubscribeHTTP(method)
		default:
			aerc.Logger().Printf("skipping unrecognized scheme: %s", method.Scheme)
		}
	}
	return errors.New("no supported unsubscribe methods found")
}

// parseUnsubscribeMethods reads the list-unsubscribe header and parses it as a
// list of angle-bracket <> deliminated URLs. See RFC 2369.
func parseUnsubscribeMethods(header string) (methods []*url.URL) {
1 reference
r := bufio.NewReader(strings.NewReader(header)) for { // discard until < _, err := r.ReadSlice('<') if err != nil { return } // read until < m, err := r.ReadSlice('>') if err != nil { return } m = m[:len(m)-1] if u, err := url.Parse(string(m)); err == nil { methods = append(methods, u) } } } func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
1 reference
widget := aerc.SelectedTab().(widgets.ProvidesMessage) acct := widget.SelectedAccount() defaults := map[string]string{ "To": u.Opaque, "Subject": u.Query().Get("subject"), } composer := widgets.NewComposer( aerc.Config(), acct.AccountConfig(), acct.Worker(), defaults, ) composer.SetContents(strings.NewReader(u.Query().Get("body"))) tab := aerc.NewTab(composer, "unsubscribe") composer.OnHeaderChange("Subject", func(subject string) { if subject == "" { tab.Name = "unsubscribe" } else { tab.Name = subject } tab.Content.Invalidate() }) return nil } func unsubscribeHTTP(u *url.URL) error {
1 reference
return lib.OpenFile(u.String()) }