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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package lib
import (
"bytes"
"io"
"io/ioutil"
"github.com/emersion/go-message"
_ "github.com/emersion/go-message/charset"
"github.com/emersion/go-pgpmail"
"golang.org/x/crypto/openpgp"
"git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/lib"
)
// This is an abstraction for viewing a message with semi-transparent PGP
// support.
type MessageView interface {
// Returns the MessageInfo for this message
MessageInfo() *models.MessageInfo
// Returns the BodyStructure for this message
BodyStructure() *models.BodyStructure
// Returns the message store that this message was originally sourced from
Store() *MessageStore
// Fetches a specific body part for this message
FetchBodyPart(parent *models.BodyStructure,
part []int, cb func(io.Reader))
PGPDetails() *openpgp.MessageDetails
}
func usePGP(info *models.BodyStructure) bool {
if info.MIMEType == "application" {
if info.MIMESubType == "pgp-encrypted" ||
info.MIMESubType == "pgp-signature" {
return true
}
}
for _, part := range info.Parts {
if usePGP(part) {
return true
}
}
return false
}
type MessageStoreView struct {
messageInfo *models.MessageInfo
messageStore *MessageStore
message []byte
details *openpgp.MessageDetails
bodyStructure *models.BodyStructure
}
func NewMessageStoreView(messageInfo *models.MessageInfo,
store *MessageStore, decryptKeys openpgp.PromptFunction,
cb func(MessageView)) {
msv := &MessageStoreView{messageInfo, store,
nil, nil, messageInfo.BodyStructure}
if usePGP(messageInfo.BodyStructure) {
store.FetchFull([]uint32{messageInfo.Uid}, func(reader io.Reader) {
pgpReader, err := pgpmail.Read(reader, Keyring, decryptKeys, nil)
if err != nil {
panic(err)
}
msv.message, err = ioutil.ReadAll(pgpReader.MessageDetails.UnverifiedBody)
if err != nil {
panic(err)
}
decrypted, err := message.Read(bytes.NewBuffer(msv.message))
if err != nil {
panic(err)
}
bs, err := lib.ParseEntityStructure(decrypted)
if err != nil {
panic(err)
}
msv.bodyStructure = bs
msv.details = pgpReader.MessageDetails
cb(msv)
})
} else {
cb(msv)
}
}
func (msv *MessageStoreView) MessageInfo() *models.MessageInfo {
return msv.messageInfo
}
func (msv *MessageStoreView) BodyStructure() *models.BodyStructure {
return msv.bodyStructure
}
func (msv *MessageStoreView) Store() *MessageStore {
return msv.messageStore
}
func (msv *MessageStoreView) PGPDetails() *openpgp.MessageDetails {
return msv.details
}
func (msv *MessageStoreView) FetchBodyPart(parent *models.BodyStructure,
part []int, cb func(io.Reader)) {
if msv.message == nil {
msv.messageStore.FetchBodyPart(msv.messageInfo.Uid, parent, part, cb)
return
}
buf := bytes.NewBuffer(msv.message)
msg, err := message.Read(buf)
if err != nil {
panic(err)
}
reader, err := lib.FetchEntityPartReader(msg, part)
if err != nil {
panic(err)
}
cb(reader)
}
|