Replace parts tree with attachment list
This commit is contained in:
parent
09d19169da
commit
4904207269
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
git.sr.ht/~sircmpwn/dowork v0.0.0-20201013174036-53a05612a082
|
git.sr.ht/~sircmpwn/dowork v0.0.0-20201013174036-53a05612a082
|
||||||
github.com/aymerick/douceur v0.2.0
|
github.com/aymerick/douceur v0.2.0
|
||||||
github.com/chris-ramon/douceur v0.2.0
|
github.com/chris-ramon/douceur v0.2.0
|
||||||
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1
|
github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1
|
||||||
github.com/emersion/go-imap v1.0.4
|
github.com/emersion/go-imap v1.0.4
|
||||||
github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915
|
github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -22,6 +22,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||||
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e h1:YGM1sI7edZOt8KAfX9Miq/X99d2QXdgjkJ7vN4HjxAA=
|
github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e h1:YGM1sI7edZOt8KAfX9Miq/X99d2QXdgjkJ7vN4HjxAA=
|
||||||
github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e/go.mod h1:4xVTBPcT43a1pp3vdaa+FuRdX5XhKCZPpWv7m0z9ByM=
|
github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e/go.mod h1:4xVTBPcT43a1pp3vdaa+FuRdX5XhKCZPpWv7m0z9ByM=
|
||||||
github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 h1:v0W797seT60q3pzrphQUKh22Nt8uS7rgZyD6lqYgM0E=
|
github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 h1:v0W797seT60q3pzrphQUKh22Nt8uS7rgZyD6lqYgM0E=
|
||||||
|
|
|
@ -10,11 +10,12 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/emersion/go-imap"
|
"github.com/emersion/go-imap"
|
||||||
imapspecialuse "github.com/emersion/go-imap-specialuse"
|
|
||||||
imapclient "github.com/emersion/go-imap/client"
|
|
||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
"github.com/emersion/go-message/textproto"
|
"github.com/emersion/go-message/textproto"
|
||||||
|
imapclient "github.com/emersion/go-imap/client"
|
||||||
|
imapspecialuse "github.com/emersion/go-imap-specialuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MailboxInfo struct {
|
type MailboxInfo struct {
|
||||||
|
@ -177,6 +178,7 @@ func newIMAPPartNode(msg *IMAPMessage, path []int, part *imap.BodyStructure) *IM
|
||||||
MIMEType: strings.ToLower(part.MIMEType + "/" + part.MIMESubType),
|
MIMEType: strings.ToLower(part.MIMEType + "/" + part.MIMESubType),
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Message: msg,
|
Message: msg,
|
||||||
|
Size: part.Size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +303,7 @@ type IMAPPartNode struct {
|
||||||
Filename string
|
Filename string
|
||||||
Children []IMAPPartNode
|
Children []IMAPPartNode
|
||||||
Message *IMAPMessage
|
Message *IMAPMessage
|
||||||
|
Size uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node IMAPPartNode) PathString() string {
|
func (node IMAPPartNode) PathString() string {
|
||||||
|
@ -308,10 +311,13 @@ func (node IMAPPartNode) PathString() string {
|
||||||
for i, partNum := range node.Path {
|
for i, partNum := range node.Path {
|
||||||
l[i] = strconv.Itoa(partNum)
|
l[i] = strconv.Itoa(partNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(l, ".")
|
return strings.Join(l, ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (node IMAPPartNode) SizeString() string {
|
||||||
|
return humanize.IBytes(uint64(node.Size))
|
||||||
|
}
|
||||||
|
|
||||||
func (node IMAPPartNode) URL(raw bool) *url.URL {
|
func (node IMAPPartNode) URL(raw bool) *url.URL {
|
||||||
u := node.Message.URL()
|
u := node.Message.URL()
|
||||||
if raw {
|
if raw {
|
||||||
|
@ -348,6 +354,7 @@ func imapPartTree(msg *IMAPMessage, bs *imap.BodyStructure, path []int) *IMAPPar
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Children: make([]IMAPPartNode, len(bs.Parts)),
|
Children: make([]IMAPPartNode, len(bs.Parts)),
|
||||||
Message: msg,
|
Message: msg,
|
||||||
|
Size: bs.Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, part := range bs.Parts {
|
for i, part := range bs.Parts {
|
||||||
|
@ -396,7 +403,12 @@ func listMessages(conn *imapclient.Client, mbox *MailboxStatus, page, messagesPe
|
||||||
var seqSet imap.SeqSet
|
var seqSet imap.SeqSet
|
||||||
seqSet.AddRange(uint32(from), uint32(to))
|
seqSet.AddRange(uint32(from), uint32(to))
|
||||||
|
|
||||||
fetch := []imap.FetchItem{imap.FetchFlags, imap.FetchEnvelope, imap.FetchUid, imap.FetchBodyStructure}
|
fetch := []imap.FetchItem{
|
||||||
|
imap.FetchFlags,
|
||||||
|
imap.FetchEnvelope,
|
||||||
|
imap.FetchUid,
|
||||||
|
imap.FetchBodyStructure,
|
||||||
|
}
|
||||||
|
|
||||||
ch := make(chan *imap.Message, 10)
|
ch := make(chan *imap.Message, 10)
|
||||||
done := make(chan error, 1)
|
done := make(chan error, 1)
|
||||||
|
@ -452,7 +464,12 @@ func searchMessages(conn *imapclient.Client, mboxName, query string, page, messa
|
||||||
var seqSet imap.SeqSet
|
var seqSet imap.SeqSet
|
||||||
seqSet.AddNum(nums...)
|
seqSet.AddNum(nums...)
|
||||||
|
|
||||||
fetch := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchUid, imap.FetchBodyStructure}
|
fetch := []imap.FetchItem{
|
||||||
|
imap.FetchEnvelope,
|
||||||
|
imap.FetchFlags,
|
||||||
|
imap.FetchUid,
|
||||||
|
imap.FetchBodyStructure,
|
||||||
|
}
|
||||||
|
|
||||||
ch := make(chan *imap.Message, 10)
|
ch := make(chan *imap.Message, 10)
|
||||||
done := make(chan error, 1)
|
done := make(chan error, 1)
|
||||||
|
@ -506,6 +523,7 @@ func getMessagePart(conn *imapclient.Client, mboxName string, uid uint32, partPa
|
||||||
imap.FetchUid,
|
imap.FetchUid,
|
||||||
imap.FetchBodyStructure,
|
imap.FetchBodyStructure,
|
||||||
imap.FetchFlags,
|
imap.FetchFlags,
|
||||||
|
imap.FetchRFC822Size,
|
||||||
partHeaderSection.FetchItem(),
|
partHeaderSection.FetchItem(),
|
||||||
partBodySection.FetchItem(),
|
partBodySection.FetchItem(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,14 +261,21 @@ main.message .message-header {
|
||||||
}
|
}
|
||||||
|
|
||||||
main.message .message-header .parts {
|
main.message .message-header .parts {
|
||||||
|
width: 30%;
|
||||||
margin-left: 0.3rem;
|
margin-left: 0.3rem;
|
||||||
padding: 0.3rem 1rem;
|
padding: 0.3rem 0.5rem;
|
||||||
background: white;
|
background: white;
|
||||||
border-top: 1px solid #f2f2f2;
|
border-top: 1px solid #f2f2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
main.message .message-header .parts ul {
|
main.message .message-header .parts ul {
|
||||||
margin-left: 1rem;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
main.message .message-header .parts li {
|
||||||
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
main.contact dl {
|
main.contact dl {
|
||||||
|
|
|
@ -2,32 +2,6 @@
|
||||||
{{template "nav.html" .}}
|
{{template "nav.html" .}}
|
||||||
{{template "util.html" .}}
|
{{template "util.html" .}}
|
||||||
|
|
||||||
{{define "message-part-tree"}}
|
|
||||||
{{/* nested templates can't access the parent's context */}}
|
|
||||||
{{$ = index . 0}}
|
|
||||||
{{with index . 1}}
|
|
||||||
<a
|
|
||||||
class="nav-link"
|
|
||||||
{{if .IsText}}
|
|
||||||
href="?part={{.PathString}}"
|
|
||||||
{{else}}
|
|
||||||
href="{{$.Message.URL}}raw?part={{.PathString}}"
|
|
||||||
{{end}}
|
|
||||||
>
|
|
||||||
{{if eq $.Part.PathString .PathString}}<strong>{{end}}
|
|
||||||
{{.String}}
|
|
||||||
{{if eq $.Part.PathString .PathString}}</strong>{{end}}
|
|
||||||
</a>
|
|
||||||
{{if gt (len .Children) 0}}
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
{{range .Children}}
|
|
||||||
<li class="nav-item">{{template "message-part-tree" (tuple $ .)}}</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
<div class="page-wrap">
|
<div class="page-wrap">
|
||||||
{{ $current := .Mailbox }}
|
{{ $current := .Mailbox }}
|
||||||
{{ template "aside" . }}
|
{{ template "aside" . }}
|
||||||
|
@ -162,9 +136,32 @@
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</table>
|
</table>
|
||||||
|
{{ $attachments := .Message.Attachments }}
|
||||||
|
{{ if $attachments }}
|
||||||
<section class="parts">
|
<section class="parts">
|
||||||
{{template "message-part-tree" (tuple $ .Message.PartTree)}}
|
<h3>Attachments</h3>
|
||||||
|
<ul>
|
||||||
|
{{ range .Message.Attachments }}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
class="nav-link"
|
||||||
|
{{if .IsText}}
|
||||||
|
href="?part={{.PathString}}"
|
||||||
|
{{else}}
|
||||||
|
href="{{$.Message.URL}}/raw?part={{.PathString}}"
|
||||||
|
{{end}}
|
||||||
|
>
|
||||||
|
{{- if .Filename -}}
|
||||||
|
{{.Filename}}
|
||||||
|
{{- else -}}
|
||||||
|
(no filename)
|
||||||
|
{{- end -}}
|
||||||
|
</a> ({{.MIMEType}}, {{.SizeString}})
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{define "addr-list"}}
|
{{define "addr-list"}}
|
||||||
|
@ -197,6 +194,7 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="{{.Message.URL}}/raw?plain=1">Raw email</a>
|
<a href="{{.Message.URL}}/raw?plain=1">Raw email</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if .View}}
|
{{if .View}}
|
||||||
{{.View}}
|
{{.View}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
|
Loading…
Reference in a new issue