Add signatures
This adds the ability for per-account signatures in the accounts.conf config file. The signature is added to emails in the editor at the bottom of the email. This includes when forwarding, replying to, and composing emails. There are two config options: signature-file and signature-cmd. The former allows a signature to be read from a file and the latter allows an arbitrary command to be executed to return the signature. The config options have been documented in aerc-config
This commit is contained in:
parent
a93b4de6f3
commit
e2d5c456dc
8 changed files with 84 additions and 9 deletions
|
@ -29,7 +29,7 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
acct := aerc.SelectedAccount()
|
acct := aerc.SelectedAccount()
|
||||||
composer := widgets.NewComposer(
|
composer := widgets.NewComposer(aerc,
|
||||||
aerc.Config(), acct.AccountConfig(), acct.Worker(), nil)
|
aerc.Config(), acct.AccountConfig(), acct.Worker(), nil)
|
||||||
tab := aerc.NewTab(composer, "New email")
|
tab := aerc.NewTab(composer, "New email")
|
||||||
composer.OnHeaderChange("Subject", func(subject string) {
|
composer.OnHeaderChange("Subject", func(subject string) {
|
||||||
|
@ -40,7 +40,7 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
}
|
}
|
||||||
tab.Content.Invalidate()
|
tab.Content.Invalidate()
|
||||||
})
|
})
|
||||||
go composer.SetContents(strings.NewReader(body))
|
go composer.PrependContents(strings.NewReader(body))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
"To": to,
|
"To": to,
|
||||||
"Subject": subject,
|
"Subject": subject,
|
||||||
}
|
}
|
||||||
composer := widgets.NewComposer(aerc.Config(), acct.AccountConfig(),
|
composer := widgets.NewComposer(aerc, aerc.Config(), acct.AccountConfig(),
|
||||||
acct.Worker(), defaults)
|
acct.Worker(), defaults)
|
||||||
|
|
||||||
addTab := func() {
|
addTab := func() {
|
||||||
|
@ -154,7 +154,7 @@ func forwardBodyPart(store *lib.MessageStore, composer *widgets.Composer,
|
||||||
|
|
||||||
pipeout, pipein := io.Pipe()
|
pipeout, pipein := io.Pipe()
|
||||||
scanner := bufio.NewScanner(part.Body)
|
scanner := bufio.NewScanner(part.Body)
|
||||||
go composer.SetContents(pipeout)
|
go composer.PrependContents(pipeout)
|
||||||
// TODO: Let user customize the date format used here
|
// TODO: Let user customize the date format used here
|
||||||
io.WriteString(pipein, fmt.Sprintf("Forwarded message from %s on %s:\n\n",
|
io.WriteString(pipein, fmt.Sprintf("Forwarded message from %s on %s:\n\n",
|
||||||
msg.Envelope.From[0].Name,
|
msg.Envelope.From[0].Name,
|
||||||
|
|
|
@ -116,8 +116,8 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
"In-Reply-To": msg.Envelope.MessageId,
|
"In-Reply-To": msg.Envelope.MessageId,
|
||||||
}
|
}
|
||||||
|
|
||||||
composer := widgets.NewComposer(
|
composer := widgets.NewComposer(aerc, aerc.Config(),
|
||||||
aerc.Config(), acct.AccountConfig(), acct.Worker(), defaults)
|
acct.AccountConfig(), acct.Worker(), defaults)
|
||||||
|
|
||||||
if args[0] == "reply" {
|
if args[0] == "reply" {
|
||||||
composer.FocusTerminal()
|
composer.FocusTerminal()
|
||||||
|
@ -170,7 +170,7 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
|
|
||||||
pipeout, pipein := io.Pipe()
|
pipeout, pipein := io.Pipe()
|
||||||
scanner := bufio.NewScanner(part.Body)
|
scanner := bufio.NewScanner(part.Body)
|
||||||
go composer.SetContents(pipeout)
|
go composer.PrependContents(pipeout)
|
||||||
// TODO: Let user customize the date format used here
|
// TODO: Let user customize the date format used here
|
||||||
io.WriteString(pipein, fmt.Sprintf("On %s %s wrote:\n",
|
io.WriteString(pipein, fmt.Sprintf("On %s %s wrote:\n",
|
||||||
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM"),
|
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM"),
|
||||||
|
|
|
@ -88,6 +88,7 @@ func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
|
||||||
"Subject": u.Query().Get("subject"),
|
"Subject": u.Query().Get("subject"),
|
||||||
}
|
}
|
||||||
composer := widgets.NewComposer(
|
composer := widgets.NewComposer(
|
||||||
|
aerc,
|
||||||
aerc.Config(),
|
aerc.Config(),
|
||||||
acct.AccountConfig(),
|
acct.AccountConfig(),
|
||||||
acct.Worker(),
|
acct.Worker(),
|
||||||
|
|
|
@ -55,6 +55,8 @@ type AccountConfig struct {
|
||||||
Params map[string]string
|
Params map[string]string
|
||||||
Outgoing string
|
Outgoing string
|
||||||
OutgoingCredCmd string
|
OutgoingCredCmd string
|
||||||
|
SignatureFile string
|
||||||
|
SignatureCmd string
|
||||||
}
|
}
|
||||||
|
|
||||||
type BindingConfig struct {
|
type BindingConfig struct {
|
||||||
|
|
|
@ -297,6 +297,14 @@ Note that many of these configuration options are written for you, such as
|
||||||
Specifies an optional command that is run to get the source account's
|
Specifies an optional command that is run to get the source account's
|
||||||
password. See each protocol's man page for more details.
|
password. See each protocol's man page for more details.
|
||||||
|
|
||||||
|
*signature-file*
|
||||||
|
Specifies the file to read in order to obtain the signature to be added
|
||||||
|
to emails sent from this account.
|
||||||
|
|
||||||
|
*signature-cmd*
|
||||||
|
Specifies the command to execute in *sh* in order to obtain the
|
||||||
|
signature to be added to emails sent from this account. If the command
|
||||||
|
fails then *signature-file* is used instead.
|
||||||
|
|
||||||
# BINDS.CONF
|
# BINDS.CONF
|
||||||
|
|
||||||
|
|
|
@ -430,7 +430,7 @@ func (aerc *Aerc) Mailto(addr *url.URL) error {
|
||||||
defaults[header] = strings.Join(vals, ",")
|
defaults[header] = strings.Join(vals, ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
composer := NewComposer(aerc.Config(),
|
composer := NewComposer(aerc, aerc.Config(),
|
||||||
acct.AccountConfig(), acct.Worker(), defaults)
|
acct.AccountConfig(), acct.Worker(), defaults)
|
||||||
composer.FocusSubject()
|
composer.FocusSubject()
|
||||||
title := "New email"
|
title := "New email"
|
||||||
|
|
|
@ -2,6 +2,8 @@ package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime"
|
"mime"
|
||||||
|
@ -17,6 +19,7 @@ import (
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/mattn/go-runewidth"
|
"github.com/mattn/go-runewidth"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/aerc/config"
|
"git.sr.ht/~sircmpwn/aerc/config"
|
||||||
|
@ -29,6 +32,7 @@ type Composer struct {
|
||||||
|
|
||||||
acct *config.AccountConfig
|
acct *config.AccountConfig
|
||||||
config *config.AercConfig
|
config *config.AercConfig
|
||||||
|
aerc *Aerc
|
||||||
|
|
||||||
defaults map[string]string
|
defaults map[string]string
|
||||||
editor *Terminal
|
editor *Terminal
|
||||||
|
@ -48,7 +52,7 @@ type Composer struct {
|
||||||
width int
|
width int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewComposer(conf *config.AercConfig,
|
func NewComposer(aerc *Aerc, conf *config.AercConfig,
|
||||||
acct *config.AccountConfig, worker *types.Worker, defaults map[string]string) *Composer {
|
acct *config.AccountConfig, worker *types.Worker, defaults map[string]string) *Composer {
|
||||||
|
|
||||||
if defaults == nil {
|
if defaults == nil {
|
||||||
|
@ -68,6 +72,7 @@ func NewComposer(conf *config.AercConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &Composer{
|
c := &Composer{
|
||||||
|
aerc: aerc,
|
||||||
editors: editors,
|
editors: editors,
|
||||||
acct: acct,
|
acct: acct,
|
||||||
config: conf,
|
config: conf,
|
||||||
|
@ -80,6 +85,8 @@ func NewComposer(conf *config.AercConfig,
|
||||||
focusable: focusable,
|
focusable: focusable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.AddSignature()
|
||||||
|
|
||||||
c.updateGrid()
|
c.updateGrid()
|
||||||
c.ShowTerminal()
|
c.ShowTerminal()
|
||||||
|
|
||||||
|
@ -140,6 +147,63 @@ func (c *Composer) SetContents(reader io.Reader) *Composer {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Composer) PrependContents(reader io.Reader) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
c.email.Seek(0, io.SeekStart)
|
||||||
|
io.Copy(buf, c.email)
|
||||||
|
c.email.Seek(0, io.SeekStart)
|
||||||
|
io.Copy(c.email, reader)
|
||||||
|
io.Copy(c.email, buf)
|
||||||
|
c.email.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Composer) AppendContents(reader io.Reader) {
|
||||||
|
c.email.Seek(0, io.SeekEnd)
|
||||||
|
io.Copy(c.email, reader)
|
||||||
|
c.email.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Composer) AddSignature() {
|
||||||
|
var signature []byte
|
||||||
|
if c.acct.SignatureCmd != "" {
|
||||||
|
var err error
|
||||||
|
signature, err = c.readSignatureFromCmd()
|
||||||
|
if err != nil {
|
||||||
|
signature = c.readSignatureFromFile()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
signature = c.readSignatureFromFile()
|
||||||
|
}
|
||||||
|
c.AppendContents(bytes.NewReader(signature))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Composer) readSignatureFromCmd() ([]byte, error) {
|
||||||
|
sigCmd := c.acct.SignatureCmd
|
||||||
|
cmd := exec.Command("sh", "-c", sigCmd)
|
||||||
|
signature, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Composer) readSignatureFromFile() []byte {
|
||||||
|
sigFile := c.acct.SignatureFile
|
||||||
|
if sigFile == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sigFile, err := homedir.Expand(sigFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
signature, err := ioutil.ReadFile(sigFile)
|
||||||
|
if err != nil {
|
||||||
|
c.aerc.PushError(fmt.Sprintf(" Error loading signature from file: %v", sigFile))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return signature
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Composer) FocusTerminal() *Composer {
|
func (c *Composer) FocusTerminal() *Composer {
|
||||||
if c.editor == nil {
|
if c.editor == nil {
|
||||||
return c
|
return c
|
||||||
|
|
Loading…
Reference in a new issue