about summary refs log tree commit diff stats
path: root/widgets/msgviewer.go
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2020-03-03 16:20:07 -0500
committerDrew DeVault <sir@cmpwn.com>2020-03-03 16:49:52 -0500
commitf3158b36f1f210ff54febbe82b571c1379b30c98 (patch)
tree10cde839c9517609f55b8f1057b1cf84ac592632 /widgets/msgviewer.go
parent89f1684ea4b5e680db7ff06a54b2d4e78212cd12 (diff)
downloadaerc-f3158b36f1f210ff54febbe82b571c1379b30c98.tar.gz
Initial support for PGP decryption & signatures
Diffstat (limited to 'widgets/msgviewer.go')
-rw-r--r--widgets/msgviewer.go103
1 files changed, 61 insertions, 42 deletions
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index 19a2380..36e7997 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -30,9 +30,8 @@ type MessageViewer struct {
 	conf     *config.AercConfig
 	err      error
 	grid     *ui.Grid
-	msg      *models.MessageInfo
 	switcher *PartSwitcher
-	store    *lib.MessageStore
+	msg      lib.MessageView
 }
 
 type PartSwitcher struct {
@@ -46,8 +45,8 @@ type PartSwitcher struct {
 	mv     *MessageViewer
 }
 
-func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
-	store *lib.MessageStore, msg *models.MessageInfo) *MessageViewer {
+func NewMessageViewer(acct *AccountView,
+	conf *config.AercConfig, msg lib.MessageView) *MessageViewer {
 
 	hf := HeaderLayoutFilter{
 		layout: HeaderLayout(conf.Viewer.HeaderLayout),
@@ -58,25 +57,40 @@ func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
 			return false
 		},
 	}
-	layout := hf.forMessage(msg)
+	layout := hf.forMessage(msg.MessageInfo())
 	header, headerHeight := layout.grid(
 		func(header string) ui.Drawable {
 			return &HeaderView{
-				Name:  header,
-				Value: fmtHeader(msg, header, acct.UiConfig().TimestampFormat),
+				Name: header,
+				Value: fmtHeader(msg.MessageInfo(), header,
+					acct.UiConfig().TimestampFormat),
 			}
 		},
 	)
 
-	grid := ui.NewGrid().Rows([]ui.GridSpec{
+	rows := []ui.GridSpec{
 		{ui.SIZE_EXACT, headerHeight},
+	}
+
+	if msg.PGPDetails() != nil {
+		height := 1
+		if msg.PGPDetails().IsSigned && msg.PGPDetails().IsEncrypted {
+			height = 2
+		}
+		rows = append(rows, ui.GridSpec{ui.SIZE_EXACT, height})
+	}
+
+	rows = append(rows, []ui.GridSpec{
+		{ui.SIZE_EXACT, 1},
 		{ui.SIZE_WEIGHT, 1},
-	}).Columns([]ui.GridSpec{
+	}...)
+
+	grid := ui.NewGrid().Rows(rows).Columns([]ui.GridSpec{
 		{ui.SIZE_WEIGHT, 1},
 	})
 
 	switcher := &PartSwitcher{}
-	err := createSwitcher(acct, switcher, conf, store, msg)
+	err := createSwitcher(acct, switcher, conf, msg)
 	if err != nil {
 		return &MessageViewer{
 			err:  err,
@@ -86,14 +100,20 @@ func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
 	}
 
 	grid.AddChild(header).At(0, 0)
-	grid.AddChild(switcher).At(1, 0)
+	if msg.PGPDetails() != nil {
+		grid.AddChild(NewPGPInfo(msg.PGPDetails())).At(1, 0)
+		grid.AddChild(ui.NewFill(' ')).At(2, 0)
+		grid.AddChild(switcher).At(3, 0)
+	} else {
+		grid.AddChild(ui.NewFill(' ')).At(1, 0)
+		grid.AddChild(switcher).At(2, 0)
+	}
 
 	mv := &MessageViewer{
 		acct:     acct,
 		conf:     conf,
 		grid:     grid,
 		msg:      msg,
-		store:    store,
 		switcher: switcher,
 	}
 	switcher.mv = mv
@@ -122,8 +142,8 @@ func fmtHeader(msg *models.MessageInfo, header string, timefmt string) string {
 	}
 }
 
-func enumerateParts(acct *AccountView, conf *config.AercConfig, store *lib.MessageStore,
-	msg *models.MessageInfo, body *models.BodyStructure,
+func enumerateParts(acct *AccountView, conf *config.AercConfig,
+	msg lib.MessageView, body *models.BodyStructure,
 	index []int) ([]*PartViewer, error) {
 
 	var parts []*PartViewer
@@ -134,14 +154,14 @@ func enumerateParts(acct *AccountView, conf *config.AercConfig, store *lib.Messa
 			pv := &PartViewer{part: part}
 			parts = append(parts, pv)
 			subParts, err := enumerateParts(
-				acct, conf, store, msg, part, curindex)
+				acct, conf, msg, part, curindex)
 			if err != nil {
 				return nil, err
 			}
 			parts = append(parts, subParts...)
 			continue
 		}
-		pv, err := NewPartViewer(acct, conf, store, msg, part, curindex)
+		pv, err := NewPartViewer(acct, conf, msg, part, curindex)
 		if err != nil {
 			return nil, err
 		}
@@ -150,17 +170,17 @@ func enumerateParts(acct *AccountView, conf *config.AercConfig, store *lib.Messa
 	return parts, nil
 }
 
-func createSwitcher(acct *AccountView, switcher *PartSwitcher, conf *config.AercConfig,
-	store *lib.MessageStore, msg *models.MessageInfo) error {
+func createSwitcher(acct *AccountView, switcher *PartSwitcher,
+	conf *config.AercConfig, msg lib.MessageView) error {
 
 	var err error
 	switcher.selected = -1
 	switcher.showHeaders = conf.Viewer.ShowHeaders
 	switcher.alwaysShowMime = conf.Viewer.AlwaysShowMime
 
-	if len(msg.BodyStructure.Parts) == 0 {
+	if len(msg.BodyStructure().Parts) == 0 {
 		switcher.selected = 0
-		pv, err := NewPartViewer(acct, conf, store, msg, msg.BodyStructure, []int{1})
+		pv, err := NewPartViewer(acct, conf, msg, msg.BodyStructure(), []int{1})
 		if err != nil {
 			return err
 		}
@@ -169,8 +189,8 @@ func createSwitcher(acct *AccountView, switcher *PartSwitcher, conf *config.Aerc
 			switcher.Invalidate()
 		})
 	} else {
-		switcher.parts, err = enumerateParts(acct, conf, store,
-			msg, msg.BodyStructure, []int{})
+		switcher.parts, err = enumerateParts(acct, conf, msg,
+			msg.BodyStructure(), []int{})
 		if err != nil {
 			return err
 		}
@@ -228,7 +248,7 @@ func (mv *MessageViewer) OnInvalidate(fn func(d ui.Drawable)) {
 }
 
 func (mv *MessageViewer) Store() *lib.MessageStore {
-	return mv.store
+	return mv.msg.Store()
 }
 
 func (mv *MessageViewer) SelectedAccount() *AccountView {
@@ -239,7 +259,7 @@ func (mv *MessageViewer) SelectedMessage() (*models.MessageInfo, error) {
 	if mv.msg == nil {
 		return nil, errors.New("no message selected")
 	}
-	return mv.msg, nil
+	return mv.msg.MessageInfo(), nil
 }
 
 func (mv *MessageViewer) MarkedMessages() ([]*models.MessageInfo, error) {
@@ -250,8 +270,7 @@ func (mv *MessageViewer) MarkedMessages() ([]*models.MessageInfo, error) {
 func (mv *MessageViewer) ToggleHeaders() {
 	switcher := mv.switcher
 	mv.conf.Viewer.ShowHeaders = !mv.conf.Viewer.ShowHeaders
-	err := createSwitcher(
-		mv.acct, switcher, mv.conf, mv.store, mv.msg)
+	err := createSwitcher(mv.acct, switcher, mv.conf, mv.msg)
 	if err != nil {
 		mv.acct.Logger().Printf(
 			"warning: error during create switcher - %v", err)
@@ -265,9 +284,9 @@ func (mv *MessageViewer) SelectedMessagePart() *PartInfo {
 
 	return &PartInfo{
 		Index: part.index,
-		Msg:   part.msg,
+		Msg:   part.msg.MessageInfo(),
 		Part:  part.part,
-		Store: part.store,
+		Store: mv.Store(),
 	}
 }
 
@@ -420,22 +439,20 @@ type PartViewer struct {
 	fetched     bool
 	filter      *exec.Cmd
 	index       []int
-	msg         *models.MessageInfo
+	msg         lib.MessageView
 	pager       *exec.Cmd
 	pagerin     io.WriteCloser
 	part        *models.BodyStructure
 	showHeaders bool
 	sink        io.WriteCloser
 	source      io.Reader
-	store       *lib.MessageStore
 	term        *Terminal
 	selecter    *Selecter
 	grid        *ui.Grid
 }
 
 func NewPartViewer(acct *AccountView, conf *config.AercConfig,
-	store *lib.MessageStore, msg *models.MessageInfo,
-	part *models.BodyStructure,
+	msg lib.MessageView, part *models.BodyStructure,
 	index []int) (*PartViewer, error) {
 
 	var (
@@ -452,6 +469,7 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig,
 
 	pager = exec.Command(cmd[0], cmd[1:]...)
 
+	info := msg.MessageInfo()
 	for _, f := range conf.Filters {
 		mime := strings.ToLower(part.MIMEType) +
 			"/" + strings.ToLower(part.MIMESubType)
@@ -464,13 +482,13 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig,
 			var header string
 			switch f.Header {
 			case "subject":
-				header = msg.Envelope.Subject
+				header = info.Envelope.Subject
 			case "from":
-				header = models.FormatAddresses(msg.Envelope.From)
+				header = models.FormatAddresses(info.Envelope.From)
 			case "to":
-				header = models.FormatAddresses(msg.Envelope.To)
+				header = models.FormatAddresses(info.Envelope.To)
 			case "cc":
-				header = models.FormatAddresses(msg.Envelope.Cc)
+				header = models.FormatAddresses(info.Envelope.Cc)
 			}
 			if f.Regex.Match([]byte(header)) {
 				filter = exec.Command("sh", "-c", f.Command)
@@ -521,7 +539,6 @@ func NewPartViewer(acct *AccountView, conf *config.AercConfig,
 		part:        part,
 		showHeaders: conf.Viewer.ShowHeaders,
 		sink:        pipe,
-		store:       store,
 		term:        term,
 		selecter:    selecter,
 		grid:        grid,
@@ -577,11 +594,12 @@ func (pv *PartViewer) attemptCopy() {
 			}()
 		}
 		go func() {
-			if pv.showHeaders && pv.msg.RFC822Headers != nil {
+			info := pv.msg.MessageInfo()
+			if pv.showHeaders && info.RFC822Headers != nil {
 				// header need to bypass the filter, else we run into issues
 				// with the filter messing with newlines etc.
 				// hence all writes in this block go directly to the pager
-				fields := pv.msg.RFC822Headers.Fields()
+				fields := info.RFC822Headers.Fields()
 				for fields.Next() {
 					var value string
 					var err error
@@ -594,8 +612,8 @@ func (pv *PartViewer) attemptCopy() {
 					pv.pagerin.Write([]byte(field))
 				}
 				// virtual header
-				if len(pv.msg.Labels) != 0 {
-					labels := fmtHeader(pv.msg, "Labels", "")
+				if len(info.Labels) != 0 {
+					labels := fmtHeader(info, "Labels", "")
 					pv.pagerin.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
 				}
 				pv.pagerin.Write([]byte{'\n'})
@@ -635,7 +653,8 @@ func (pv *PartViewer) Draw(ctx *ui.Context) {
 		return
 	}
 	if !pv.fetched {
-		pv.store.FetchBodyPart(pv.msg.Uid, pv.msg.BodyStructure, pv.index, pv.SetSource)
+		pv.msg.FetchBodyPart(pv.msg.BodyStructure(),
+			pv.index, pv.SetSource)
 		pv.fetched = true
 	}
 	if pv.err != nil {