lint: work nicely with wrapped errors (errorlint)
Error wrapping as introduced in Go 1.13 adds some additional logic to use for comparing errors and adding information to it. Signed-off-by: Moritz Poldrack <moritz@poldrack.dev> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
978d35d356
commit
70bfcfef42
26 changed files with 163 additions and 158 deletions
|
@ -31,7 +31,7 @@ func (MoveTab) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
|
|
||||||
n, err := strconv.Atoi(joinedArgs)
|
n, err := strconv.Atoi(joinedArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse index argument: %v", err)
|
return fmt.Errorf("failed to parse index argument: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var relative bool
|
var relative bool
|
||||||
|
|
|
@ -85,7 +85,7 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
if strings.Contains(to, "@") {
|
if strings.Contains(to, "@") {
|
||||||
tolist, err = mail.ParseAddressList(to)
|
tolist, err = mail.ParseAddressList(to)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid to address(es): %v", err)
|
return fmt.Errorf("invalid to address(es): %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(tolist) > 0 {
|
if len(tolist) > 0 {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package completer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -82,14 +83,14 @@ func (c *Completer) completeAddress(s string) ([]string, string, error) {
|
||||||
}
|
}
|
||||||
stdout, err := cmd.StdoutPipe()
|
stdout, err := cmd.StdoutPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("stdout: %v", err)
|
return nil, "", fmt.Errorf("stdout: %w", err)
|
||||||
}
|
}
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("stderr: %v", err)
|
return nil, "", fmt.Errorf("stderr: %w", err)
|
||||||
}
|
}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return nil, "", fmt.Errorf("cmd start: %v", err)
|
return nil, "", fmt.Errorf("cmd start: %w", err)
|
||||||
}
|
}
|
||||||
// Wait returns an error if the exit status != 0, which some completion
|
// Wait returns an error if the exit status != 0, which some completion
|
||||||
// programs will do to signal no matches. We don't want to spam the user with
|
// programs will do to signal no matches. We don't want to spam the user with
|
||||||
|
@ -104,7 +105,7 @@ func (c *Completer) completeAddress(s string) ([]string, string, error) {
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
msg = ": " + msg
|
msg = ": " + msg
|
||||||
}
|
}
|
||||||
return nil, "", fmt.Errorf("read completions%s: %v", msg, err)
|
return nil, "", fmt.Errorf("read completions%s: %w", msg, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions, prefix, nil
|
return completions, prefix, nil
|
||||||
|
@ -150,7 +151,7 @@ func readCompletions(r io.Reader) ([]string, error) {
|
||||||
completions := []string{}
|
completions := []string{}
|
||||||
for {
|
for {
|
||||||
line, err := buf.ReadString('\n')
|
line, err := buf.ReadString('\n')
|
||||||
if err == io.EOF {
|
if errors.Is(err, io.EOF) {
|
||||||
return completions, nil
|
return completions, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -128,7 +128,7 @@ func (c RemoteConfig) ConnectionString() (string, error) {
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
output, err := cmd.Output()
|
output, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to read password: %s", err)
|
return "", fmt.Errorf("failed to read password: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pw := strings.TrimSpace(string(output))
|
pw := strings.TrimSpace(string(output))
|
||||||
|
@ -344,13 +344,13 @@ func loadAccountConfig(path string) ([]AccountConfig, error) {
|
||||||
|
|
||||||
source, err := sourceRemoteConfig.ConnectionString()
|
source, err := sourceRemoteConfig.ConnectionString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid source credentials for %s: %s", _sec, err)
|
return nil, fmt.Errorf("Invalid source credentials for %s: %w", _sec, err)
|
||||||
}
|
}
|
||||||
account.Source = source
|
account.Source = source
|
||||||
|
|
||||||
_, err = account.Outgoing.parseValue()
|
_, err = account.Outgoing.parseValue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Invalid outgoing credentials for %s: %s", _sec, err)
|
return nil, fmt.Errorf("Invalid outgoing credentials for %s: %w", _sec, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
accounts = append(accounts, account)
|
accounts = append(accounts, account)
|
||||||
|
@ -1027,7 +1027,7 @@ func (ui *UIConfig) loadStyleSet(styleSetDirs []string) error {
|
||||||
ui.style = NewStyleSet()
|
ui.style = NewStyleSet()
|
||||||
err := ui.style.LoadStyleSet(ui.StyleSetName, styleSetDirs)
|
err := ui.style.LoadStyleSet(ui.StyleSetName, styleSetDirs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Unable to load default styleset: %s", err)
|
return fmt.Errorf("Unable to load default styleset: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -33,7 +33,7 @@ func Encrypt(r io.Reader, to []string, from string) ([]byte, error) {
|
||||||
var md models.MessageDetails
|
var md models.MessageDetails
|
||||||
err = parse(outRdr, &md)
|
err = parse(outRdr, &md)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpg: failure to encrypt: %v. check public key(s)", err)
|
return nil, fmt.Errorf("gpg: failure to encrypt: %w. check public key(s)", err)
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
_, _ = io.Copy(&buf, md.Body)
|
_, _ = io.Copy(&buf, md.Body)
|
||||||
|
|
|
@ -26,7 +26,7 @@ func Sign(r io.Reader, from string) ([]byte, string, error) {
|
||||||
var md models.MessageDetails
|
var md models.MessageDetails
|
||||||
err = parse(outRdr, &md)
|
err = parse(outRdr, &md)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("failed to parse messagedetails: %v", err)
|
return nil, "", fmt.Errorf("failed to parse messagedetails: %w", err)
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
_, _ = io.Copy(&buf, md.Body)
|
_, _ = io.Copy(&buf, md.Body)
|
||||||
|
|
|
@ -61,12 +61,12 @@ func Read(r io.Reader) (*Reader, error) {
|
||||||
func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Reader, error) {
|
func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Reader, error) {
|
||||||
p, err := mr.NextPart()
|
p, err := mr.NextPart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read first part in multipart/encrypted message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read first part in multipart/encrypted message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
|
t, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to parse Content-Type of first part in multipart/encrypted message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to parse Content-Type of first part in multipart/encrypted message: %w", err)
|
||||||
}
|
}
|
||||||
if !strings.EqualFold(t, "application/pgp-encrypted") {
|
if !strings.EqualFold(t, "application/pgp-encrypted") {
|
||||||
return nil, fmt.Errorf("gpgmail: first part in multipart/encrypted message has type %q, not application/pgp-encrypted", t)
|
return nil, fmt.Errorf("gpgmail: first part in multipart/encrypted message has type %q, not application/pgp-encrypted", t)
|
||||||
|
@ -74,7 +74,7 @@ func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Rea
|
||||||
|
|
||||||
metadata, err := textproto.ReadHeader(bufio.NewReader(p))
|
metadata, err := textproto.ReadHeader(bufio.NewReader(p))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to parse application/pgp-encrypted part: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to parse application/pgp-encrypted part: %w", err)
|
||||||
}
|
}
|
||||||
if s := metadata.Get("Version"); s != "1" {
|
if s := metadata.Get("Version"); s != "1" {
|
||||||
return nil, fmt.Errorf("gpgmail: unsupported PGP/MIME version: %q", s)
|
return nil, fmt.Errorf("gpgmail: unsupported PGP/MIME version: %q", s)
|
||||||
|
@ -82,11 +82,11 @@ func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Rea
|
||||||
|
|
||||||
p, err = mr.NextPart()
|
p, err = mr.NextPart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read second part in multipart/encrypted message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read second part in multipart/encrypted message: %w", err)
|
||||||
}
|
}
|
||||||
t, _, err = mime.ParseMediaType(p.Header.Get("Content-Type"))
|
t, _, err = mime.ParseMediaType(p.Header.Get("Content-Type"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to parse Content-Type of second part in multipart/encrypted message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to parse Content-Type of second part in multipart/encrypted message: %w", err)
|
||||||
}
|
}
|
||||||
if !strings.EqualFold(t, "application/octet-stream") {
|
if !strings.EqualFold(t, "application/octet-stream") {
|
||||||
return nil, fmt.Errorf("gpgmail: second part in multipart/encrypted message has type %q, not application/octet-stream", t)
|
return nil, fmt.Errorf("gpgmail: second part in multipart/encrypted message has type %q, not application/octet-stream", t)
|
||||||
|
@ -94,13 +94,13 @@ func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Rea
|
||||||
|
|
||||||
md, err := gpgbin.Decrypt(p)
|
md, err := gpgbin.Decrypt(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read PGP message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read PGP message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cleartext := bufio.NewReader(md.Body)
|
cleartext := bufio.NewReader(md.Body)
|
||||||
cleartextHeader, err := textproto.ReadHeader(cleartext)
|
cleartextHeader, err := textproto.ReadHeader(cleartext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read encrypted header: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read encrypted header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, params, err := mime.ParseMediaType(cleartextHeader.Get("Content-Type"))
|
t, params, err := mime.ParseMediaType(cleartextHeader.Get("Content-Type"))
|
||||||
|
@ -114,7 +114,7 @@ func newEncryptedReader(h textproto.Header, mr *textproto.MultipartReader) (*Rea
|
||||||
mr := textproto.NewMultipartReader(cleartext, params["boundary"])
|
mr := textproto.NewMultipartReader(cleartext, params["boundary"])
|
||||||
mds, err := newSignedReader(cleartextHeader, mr, micalg)
|
mds, err := newSignedReader(cleartextHeader, mr, micalg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read encapsulated multipart/signed message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read encapsulated multipart/signed message: %w", err)
|
||||||
}
|
}
|
||||||
mds.MessageDetails.IsEncrypted = md.IsEncrypted
|
mds.MessageDetails.IsEncrypted = md.IsEncrypted
|
||||||
mds.MessageDetails.DecryptedWith = md.DecryptedWith
|
mds.MessageDetails.DecryptedWith = md.DecryptedWith
|
||||||
|
@ -136,7 +136,7 @@ func newSignedReader(h textproto.Header, mr *textproto.MultipartReader, micalg s
|
||||||
micalg = strings.ToLower(micalg)
|
micalg = strings.ToLower(micalg)
|
||||||
p, err := mr.NextPart()
|
p, err := mr.NextPart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read signed part in multipart/signed message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read signed part in multipart/signed message: %w", err)
|
||||||
}
|
}
|
||||||
var headerBuf bytes.Buffer
|
var headerBuf bytes.Buffer
|
||||||
_ = textproto.WriteHeader(&headerBuf, p.Header)
|
_ = textproto.WriteHeader(&headerBuf, p.Header)
|
||||||
|
@ -147,12 +147,12 @@ func newSignedReader(h textproto.Header, mr *textproto.MultipartReader, micalg s
|
||||||
|
|
||||||
sig, err := mr.NextPart()
|
sig, err := mr.NextPart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read pgp part in multipart/signed message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read pgp part in multipart/signed message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
md, err := gpgbin.Verify(&msg, sig)
|
md, err := gpgbin.Verify(&msg, sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("gpgmail: failed to read PGP message: %v", err)
|
return nil, fmt.Errorf("gpgmail: failed to read PGP message: %w", err)
|
||||||
}
|
}
|
||||||
if md.Micalg != micalg && md.SignatureError == "" {
|
if md.Micalg != micalg && md.SignatureError == "" {
|
||||||
md.SignatureError = "gpg: header hash does not match actual sig hash"
|
md.SignatureError = "gpg: header hash does not match actual sig hash"
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (m *Mail) Init() error {
|
||||||
logging.Infof("Initializing PGP keyring")
|
logging.Infof("Initializing PGP keyring")
|
||||||
err := os.MkdirAll(path.Join(xdg.DataHome(), "aerc"), 0o700)
|
err := os.MkdirAll(path.Join(xdg.DataHome(), "aerc"), 0o700)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create data directory: %v", err)
|
return fmt.Errorf("failed to create data directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockpath := path.Join(xdg.DataHome(), "aerc", "keyring.lock")
|
lockpath := path.Join(xdg.DataHome(), "aerc", "keyring.lock")
|
||||||
|
@ -290,16 +290,16 @@ func (m *Mail) ExportKey(k string) (io.Reader, error) {
|
||||||
pks := bytes.NewBuffer(nil)
|
pks := bytes.NewBuffer(nil)
|
||||||
err = entity.Serialize(pks)
|
err = entity.Serialize(pks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("pgp: error exporting key: %v", err)
|
return nil, fmt.Errorf("pgp: error exporting key: %w", err)
|
||||||
}
|
}
|
||||||
pka := bytes.NewBuffer(nil)
|
pka := bytes.NewBuffer(nil)
|
||||||
w, err := armor.Encode(pka, "PGP PUBLIC KEY BLOCK", map[string]string{})
|
w, err := armor.Encode(pka, "PGP PUBLIC KEY BLOCK", map[string]string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("pgp: error exporting key: %v", err)
|
return nil, fmt.Errorf("pgp: error exporting key: %w", err)
|
||||||
}
|
}
|
||||||
_, err = w.Write(pks.Bytes())
|
_, err = w.Write(pks.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("pgp: error exporting key: %v", err)
|
return nil, fmt.Errorf("pgp: error exporting key: %w", err)
|
||||||
}
|
}
|
||||||
w.Close()
|
w.Close()
|
||||||
return pka, nil
|
return pka, nil
|
||||||
|
|
|
@ -23,7 +23,7 @@ func (c *OAuthBearer) ExchangeRefreshToken(refreshToken string) (*oauth2.Token,
|
||||||
|
|
||||||
func (c *OAuthBearer) Authenticate(username string, password string, client *client.Client) error {
|
func (c *OAuthBearer) Authenticate(username string, password string, client *client.Client) error {
|
||||||
if ok, err := client.SupportAuth(sasl.OAuthBearer); err != nil || !ok {
|
if ok, err := client.SupportAuth(sasl.OAuthBearer); err != nil || !ok {
|
||||||
return fmt.Errorf("OAuthBearer not supported %v", err)
|
return fmt.Errorf("OAuthBearer not supported %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.OAuth2.Endpoint.TokenURL != "" {
|
if c.OAuth2.Endpoint.TokenURL != "" {
|
||||||
|
|
|
@ -404,7 +404,7 @@ func (acct *AccountView) GetSortCriteria() []*types.SortCriterion {
|
||||||
}
|
}
|
||||||
criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort)
|
criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
acct.PushError(fmt.Errorf("ui sort: %v", err))
|
acct.PushError(fmt.Errorf("ui sort: %w", err))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return criteria
|
return criteria
|
||||||
|
|
|
@ -536,7 +536,7 @@ func (aerc *Aerc) Mailto(addr *url.URL) error {
|
||||||
h := &mail.Header{}
|
h := &mail.Header{}
|
||||||
to, err := mail.ParseAddressList(addr.Opaque)
|
to, err := mail.ParseAddressList(addr.Opaque)
|
||||||
if err != nil && addr.Opaque != "" {
|
if err != nil && addr.Opaque != "" {
|
||||||
return fmt.Errorf("Could not parse to: %v", err)
|
return fmt.Errorf("Could not parse to: %w", err)
|
||||||
}
|
}
|
||||||
h.SetAddressList("to", to)
|
h.SetAddressList("to", to)
|
||||||
for key, vals := range addr.Query() {
|
for key, vals := range addr.Query() {
|
||||||
|
|
|
@ -202,7 +202,7 @@ func (c *Composer) SetAttachKey(attach bool) error {
|
||||||
if found {
|
if found {
|
||||||
err := c.DeleteAttachment(name)
|
err := c.DeleteAttachment(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to delete attachment '%s: %v", name, err)
|
return fmt.Errorf("failed to delete attachment '%s: %w", name, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
attach = !attach
|
attach = !attach
|
||||||
|
@ -259,7 +259,7 @@ func (c *Composer) SetSign(sign bool) error {
|
||||||
err := c.updateCrypto()
|
err := c.updateCrypto()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sign = !sign
|
c.sign = !sign
|
||||||
return fmt.Errorf("Cannot sign message: %v", err)
|
return fmt.Errorf("Cannot sign message: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ func (c *Composer) AddTemplate(template string, data interface{}) error {
|
||||||
|
|
||||||
mr, err := mail.CreateReader(templateText)
|
mr, err := mail.CreateReader(templateText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Template loading failed: %v", err)
|
return fmt.Errorf("Template loading failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the headers contained in the template to the compose headers
|
// copy the headers contained in the template to the compose headers
|
||||||
|
@ -414,7 +414,7 @@ func (c *Composer) AddTemplate(template string, data interface{}) error {
|
||||||
|
|
||||||
part, err := mr.NextPart()
|
part, err := mr.NextPart()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not get body of template: %v", err)
|
return fmt.Errorf("Could not get body of template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.AppendContents(part.Body)
|
c.AppendContents(part.Body)
|
||||||
|
|
|
@ -65,7 +65,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid idle-timeout value %v: %v",
|
"invalid idle-timeout value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.idle_timeout = val
|
w.config.idle_timeout = val
|
||||||
|
@ -73,7 +73,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid idle-debounce value %v: %v",
|
"invalid idle-debounce value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.idle_debounce = val
|
w.config.idle_debounce = val
|
||||||
|
@ -81,7 +81,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid reconnect-maxwait value %v: %v",
|
"invalid reconnect-maxwait value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.reconnect_maxwait = val
|
w.config.reconnect_maxwait = val
|
||||||
|
@ -89,7 +89,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid connection-timeout value %v: %v",
|
"invalid connection-timeout value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.connection_timeout = val
|
w.config.connection_timeout = val
|
||||||
|
@ -97,7 +97,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid keepalive-period value %v: %v",
|
"invalid keepalive-period value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.keepalive_period = val
|
w.config.keepalive_period = val
|
||||||
|
@ -105,7 +105,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := strconv.Atoi(value)
|
val, err := strconv.Atoi(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid keepalive-probes value %v: %v",
|
"invalid keepalive-probes value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.keepalive_probes = val
|
w.config.keepalive_probes = val
|
||||||
|
@ -113,7 +113,7 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"invalid keepalive-interval value %v: %v",
|
"invalid keepalive-interval value %v: %w",
|
||||||
value, err)
|
value, err)
|
||||||
}
|
}
|
||||||
w.config.keepalive_interval = int(val.Seconds())
|
w.config.keepalive_interval = int(val.Seconds())
|
||||||
|
@ -123,13 +123,13 @@ func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
|
||||||
// Return an error here because the user tried to set header
|
// Return an error here because the user tried to set header
|
||||||
// caching, and we want them to know they didn't set it right -
|
// caching, and we want them to know they didn't set it right -
|
||||||
// one way or the other
|
// one way or the other
|
||||||
return fmt.Errorf("invalid cache-headers value %v: %v", value, err)
|
return fmt.Errorf("invalid cache-headers value %v: %w", value, err)
|
||||||
}
|
}
|
||||||
w.config.cacheEnabled = cache
|
w.config.cacheEnabled = cache
|
||||||
case "cache-max-age":
|
case "cache-max-age":
|
||||||
val, err := time.ParseDuration(value)
|
val, err := time.ParseDuration(value)
|
||||||
if err != nil || val < 0 {
|
if err != nil || val < 0 {
|
||||||
return fmt.Errorf("invalid cache-max-age value %v: %v", value, err)
|
return fmt.Errorf("invalid cache-max-age value %v: %w", value, err)
|
||||||
}
|
}
|
||||||
w.config.cacheMaxAge = val
|
w.config.cacheMaxAge = val
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,13 +118,13 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
|
||||||
}
|
}
|
||||||
h, err := textproto.ReadHeader(bufio.NewReader(body))
|
h, err := textproto.ReadHeader(bufio.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read part header: %v", err)
|
return fmt.Errorf("failed to read part header: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
part, err := message.New(message.Header{Header: h},
|
part, err := message.New(message.Header{Header: h},
|
||||||
_msg.GetBody(&partBodySection))
|
_msg.GetBody(&partBodySection))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create message reader: %v", err)
|
return fmt.Errorf("failed to create message reader: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
imapw.worker.PostMessage(&types.MessageBodyPart{
|
imapw.worker.PostMessage(&types.MessageBodyPart{
|
||||||
|
|
|
@ -282,7 +282,7 @@ func (w *IMAPWorker) Run() {
|
||||||
case msg := <-w.worker.Actions:
|
case msg := <-w.worker.Actions:
|
||||||
msg = w.worker.ProcessAction(msg)
|
msg = w.worker.ProcessAction(msg)
|
||||||
|
|
||||||
if err := w.handleMessage(msg); err == errUnsupported {
|
if err := w.handleMessage(msg); errors.Is(err, errUnsupported) {
|
||||||
w.worker.PostMessage(&types.Unsupported{
|
w.worker.PostMessage(&types.Unsupported{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
|
@ -104,7 +104,7 @@ func ParseEntityStructure(e *message.Entity) (*models.BodyStructure, error) {
|
||||||
if cd := e.Header.Get("content-disposition"); cd != "" {
|
if cd := e.Header.Get("content-disposition"); cd != "" {
|
||||||
contentDisposition, cdParams, err := e.Header.ContentDisposition()
|
contentDisposition, cdParams, err := e.Header.ContentDisposition()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse content disposition: %v", err)
|
return nil, fmt.Errorf("could not parse content disposition: %w", err)
|
||||||
}
|
}
|
||||||
body.Disposition = contentDisposition
|
body.Disposition = contentDisposition
|
||||||
body.DispositionParams = cdParams
|
body.DispositionParams = cdParams
|
||||||
|
@ -113,7 +113,7 @@ func ParseEntityStructure(e *message.Entity) (*models.BodyStructure, error) {
|
||||||
if mpr := e.MultipartReader(); mpr != nil {
|
if mpr := e.MultipartReader(); mpr != nil {
|
||||||
for {
|
for {
|
||||||
part, err := mpr.NextPart()
|
part, err := mpr.NextPart()
|
||||||
if err == io.EOF {
|
if errors.Is(err, io.EOF) {
|
||||||
return &body, nil
|
return &body, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -133,27 +133,27 @@ var DateParseError = errors.New("date parsing failed")
|
||||||
func parseEnvelope(h *mail.Header) (*models.Envelope, error) {
|
func parseEnvelope(h *mail.Header) (*models.Envelope, error) {
|
||||||
from, err := parseAddressList(h, "from")
|
from, err := parseAddressList(h, "from")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read from address: %v", err)
|
return nil, fmt.Errorf("could not read from address: %w", err)
|
||||||
}
|
}
|
||||||
to, err := parseAddressList(h, "to")
|
to, err := parseAddressList(h, "to")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read to address: %v", err)
|
return nil, fmt.Errorf("could not read to address: %w", err)
|
||||||
}
|
}
|
||||||
cc, err := parseAddressList(h, "cc")
|
cc, err := parseAddressList(h, "cc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read cc address: %v", err)
|
return nil, fmt.Errorf("could not read cc address: %w", err)
|
||||||
}
|
}
|
||||||
bcc, err := parseAddressList(h, "bcc")
|
bcc, err := parseAddressList(h, "bcc")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read bcc address: %v", err)
|
return nil, fmt.Errorf("could not read bcc address: %w", err)
|
||||||
}
|
}
|
||||||
replyTo, err := parseAddressList(h, "reply-to")
|
replyTo, err := parseAddressList(h, "reply-to")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read reply-to address: %v", err)
|
return nil, fmt.Errorf("could not read reply-to address: %w", err)
|
||||||
}
|
}
|
||||||
subj, err := h.Subject()
|
subj, err := h.Subject()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read subject: %v", err)
|
return nil, fmt.Errorf("could not read subject: %w", err)
|
||||||
}
|
}
|
||||||
msgID, err := h.MessageID()
|
msgID, err := h.MessageID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -167,7 +167,7 @@ func parseEnvelope(h *mail.Header) (*models.Envelope, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// still return a valid struct plus a sentinel date parsing error
|
// still return a valid struct plus a sentinel date parsing error
|
||||||
// if only the date parsing failed
|
// if only the date parsing failed
|
||||||
err = fmt.Errorf("%w: %v", DateParseError, err)
|
err = fmt.Errorf("%v: %w", DateParseError, err)
|
||||||
}
|
}
|
||||||
return &models.Envelope{
|
return &models.Envelope{
|
||||||
Date: date,
|
Date: date,
|
||||||
|
@ -217,7 +217,7 @@ func parseDate(h *mail.Header) (time.Time, error) {
|
||||||
func parseReceivedHeader(h *mail.Header) (time.Time, error) {
|
func parseReceivedHeader(h *mail.Header) (time.Time, error) {
|
||||||
guess, err := h.Text("received")
|
guess, err := h.Text("received")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, fmt.Errorf("received header not parseable: %v",
|
return time.Time{}, fmt.Errorf("received header not parseable: %w",
|
||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
return time.Parse(time.RFC1123Z, dateRe.FindString(guess))
|
return time.Parse(time.RFC1123Z, dateRe.FindString(guess))
|
||||||
|
@ -254,18 +254,18 @@ func MessageInfo(raw RawMessage) (*models.MessageInfo, error) {
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
msg, err := message.Read(r)
|
msg, err := message.Read(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read message: %v", err)
|
return nil, fmt.Errorf("could not read message: %w", err)
|
||||||
}
|
}
|
||||||
bs, err := ParseEntityStructure(msg)
|
bs, err := ParseEntityStructure(msg)
|
||||||
if errors.As(err, new(message.UnknownEncodingError)) {
|
if errors.As(err, new(message.UnknownEncodingError)) {
|
||||||
parseErr = err
|
parseErr = err
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, fmt.Errorf("could not get structure: %v", err)
|
return nil, fmt.Errorf("could not get structure: %w", err)
|
||||||
}
|
}
|
||||||
h := &mail.Header{Header: msg.Header}
|
h := &mail.Header{Header: msg.Header}
|
||||||
env, err := parseEnvelope(h)
|
env, err := parseEnvelope(h)
|
||||||
if err != nil && !errors.Is(err, DateParseError) {
|
if err != nil && !errors.Is(err, DateParseError) {
|
||||||
return nil, fmt.Errorf("could not parse envelope: %v", err)
|
return nil, fmt.Errorf("could not parse envelope: %w", err)
|
||||||
// if only the date parsing failed we still get the rest of the
|
// if only the date parsing failed we still get the rest of the
|
||||||
// envelop structure in a valid state.
|
// envelop structure in a valid state.
|
||||||
// Date parsing errors are fairly common and it's better to be
|
// Date parsing errors are fairly common and it's better to be
|
||||||
|
|
|
@ -50,7 +50,7 @@ func (c *Container) ListFolders() ([]string, error) {
|
||||||
}
|
}
|
||||||
err := filepath.Walk(c.dir, func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk(c.dir, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Invalid path '%s': error: %v", path, err)
|
return fmt.Errorf("Invalid path '%s': error: %w", path, err)
|
||||||
}
|
}
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
|
@ -144,7 +144,7 @@ func (c *Container) ClearRecentFlag(uid uint32) {
|
||||||
func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
|
func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
|
||||||
keys, err := d.Keys()
|
keys, err := d.Keys()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not get keys for %s: %v", d, err)
|
return nil, fmt.Errorf("could not get keys for %s: %w", d, err)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
var uids []uint32
|
var uids []uint32
|
||||||
|
@ -189,7 +189,7 @@ func (c *Container) CopyAll(
|
||||||
) error {
|
) error {
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
if err := c.copyMessage(dest, src, uid); err != nil {
|
if err := c.copyMessage(dest, src, uid); err != nil {
|
||||||
return fmt.Errorf("could not copy message %d: %v", uid, err)
|
return fmt.Errorf("could not copy message %d: %w", uid, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (m Message) SetFlags(flags []maildir.Flag) error {
|
||||||
func (m Message) SetOneFlag(flag maildir.Flag, enable bool) error {
|
func (m Message) SetOneFlag(flag maildir.Flag, enable bool) error {
|
||||||
flags, err := m.Flags()
|
flags, err := m.Flags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not read previous flags: %v", err)
|
return fmt.Errorf("could not read previous flags: %w", err)
|
||||||
}
|
}
|
||||||
if enable {
|
if enable {
|
||||||
flags = append(flags, flag)
|
flags = append(flags, flag)
|
||||||
|
@ -87,7 +87,7 @@ func (m Message) NewBodyPartReader(requestedParts []int) (io.Reader, error) {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
msg, err := message.Read(f)
|
msg, err := message.Read(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read message: %v", err)
|
return nil, fmt.Errorf("could not read message: %w", err)
|
||||||
}
|
}
|
||||||
return lib.FetchEntityPartReader(msg, requestedParts)
|
return lib.FetchEntityPartReader(msg, requestedParts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ type Worker struct {
|
||||||
func NewWorker(worker *types.Worker) (types.Backend, error) {
|
func NewWorker(worker *types.Worker) (types.Backend, error) {
|
||||||
watch, err := fsnotify.NewWatcher()
|
watch, err := fsnotify.NewWatcher()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create file system watcher: %v", err)
|
return nil, fmt.Errorf("could not create file system watcher: %w", err)
|
||||||
}
|
}
|
||||||
return &Worker{worker: worker, watcher: watch}, nil
|
return &Worker{worker: worker, watcher: watch}, nil
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func NewWorker(worker *types.Worker) (types.Backend, error) {
|
||||||
func NewMaildirppWorker(worker *types.Worker) (types.Backend, error) {
|
func NewMaildirppWorker(worker *types.Worker) (types.Backend, error) {
|
||||||
watch, err := fsnotify.NewWatcher()
|
watch, err := fsnotify.NewWatcher()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not create file system watcher: %v", err)
|
return nil, fmt.Errorf("could not create file system watcher: %w", err)
|
||||||
}
|
}
|
||||||
return &Worker{worker: worker, watcher: watch, maildirpp: true}, nil
|
return &Worker{worker: worker, watcher: watch, maildirpp: true}, nil
|
||||||
}
|
}
|
||||||
|
@ -112,18 +112,18 @@ func (w *Worker) handleFSEvent(ev fsnotify.Event) {
|
||||||
}
|
}
|
||||||
err := w.c.SyncNewMail(*w.selected)
|
err := w.c.SyncNewMail(*w.selected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not move new to cur : %v", err)
|
logging.Errorf("could not move new to cur : %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
uids, err := w.c.UIDs(*w.selected)
|
uids, err := w.c.UIDs(*w.selected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not scan UIDs: %v", err)
|
logging.Errorf("could not scan UIDs: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sortedUids, err := w.sort(uids, w.currentSortCriteria)
|
sortedUids, err := w.sort(uids, w.currentSortCriteria)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("error sorting directory: %v", err)
|
logging.Errorf("error sorting directory: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.worker.PostMessage(&types.DirectoryContents{
|
w.worker.PostMessage(&types.DirectoryContents{
|
||||||
|
@ -204,18 +204,18 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
|
||||||
for _, v := range files {
|
for _, v := range files {
|
||||||
key, flags, err := splitMaildirFile(v)
|
key, flags, err := splitMaildirFile(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("%q: error parsing flags (%q): %v", v, key, err)
|
logging.Errorf("%q: error parsing flags (%q): %w", v, key, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
keyFlags[key] = flags
|
keyFlags[key] = flags
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logging.Infof("disabled flags cache: %q: %v", dir, err)
|
logging.Infof("disabled flags cache: %q: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uids, err := w.c.UIDs(dir)
|
uids, err := w.c.UIDs(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get uids: %v", err)
|
logging.Errorf("could not get uids: %w", err)
|
||||||
return dirInfo
|
return dirInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
message, err := w.c.Message(dir, uid)
|
message, err := w.c.Message(dir, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var flags []maildir.Flag
|
var flags []maildir.Flag
|
||||||
|
@ -234,14 +234,14 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
|
||||||
logging.Debugf("message (key=%q uid=%d) not found in map cache", message.key, message.uid)
|
logging.Debugf("message (key=%q uid=%d) not found in map cache", message.key, message.uid)
|
||||||
flags, err = message.Flags()
|
flags, err = message.Flags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get flags: %v", err)
|
logging.Errorf("could not get flags: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
flags, err = message.Flags()
|
flags, err = message.Flags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get flags: %v", err)
|
logging.Errorf("could not get flags: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -306,14 +306,14 @@ func (w *Worker) handleMessage(msg types.WorkerMessage) error {
|
||||||
func (w *Worker) handleConfigure(msg *types.Configure) error {
|
func (w *Worker) handleConfigure(msg *types.Configure) error {
|
||||||
u, err := url.Parse(msg.Config.Source)
|
u, err := url.Parse(msg.Config.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("error configuring maildir worker: %v", err)
|
logging.Errorf("error configuring maildir worker: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dir := u.Path
|
dir := u.Path
|
||||||
if u.Host == "~" {
|
if u.Host == "~" {
|
||||||
home, err := os.UserHomeDir()
|
home, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not resolve home directory: %v", err)
|
return fmt.Errorf("could not resolve home directory: %w", err)
|
||||||
}
|
}
|
||||||
dir = filepath.Join(home, u.Path)
|
dir = filepath.Join(home, u.Path)
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,7 @@ func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
|
||||||
}
|
}
|
||||||
dirs, err := w.c.ListFolders()
|
dirs, err := w.c.ListFolders()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("failed listing directories: %v", err)
|
logging.Errorf("failed listing directories: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, name := range dirs {
|
for _, name := range dirs {
|
||||||
|
@ -375,11 +375,11 @@ func (w *Worker) handleOpenDirectory(msg *types.OpenDirectory) error {
|
||||||
if w.selected != nil {
|
if w.selected != nil {
|
||||||
prevDir := filepath.Join(string(*w.selected), "new")
|
prevDir := filepath.Join(string(*w.selected), "new")
|
||||||
if err := w.watcher.Remove(prevDir); err != nil {
|
if err := w.watcher.Remove(prevDir); err != nil {
|
||||||
return fmt.Errorf("could not unwatch previous directory: %v", err)
|
return fmt.Errorf("could not unwatch previous directory: %w", err)
|
||||||
}
|
}
|
||||||
prevDir = filepath.Join(string(*w.selected), "cur")
|
prevDir = filepath.Join(string(*w.selected), "cur")
|
||||||
if err := w.watcher.Remove(prevDir); err != nil {
|
if err := w.watcher.Remove(prevDir); err != nil {
|
||||||
return fmt.Errorf("could not unwatch previous directory: %v", err)
|
return fmt.Errorf("could not unwatch previous directory: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,15 +389,15 @@ func (w *Worker) handleOpenDirectory(msg *types.OpenDirectory) error {
|
||||||
// add watch paths
|
// add watch paths
|
||||||
newDir := filepath.Join(string(*w.selected), "new")
|
newDir := filepath.Join(string(*w.selected), "new")
|
||||||
if err := w.watcher.Add(newDir); err != nil {
|
if err := w.watcher.Add(newDir); err != nil {
|
||||||
return fmt.Errorf("could not add watch to directory: %v", err)
|
return fmt.Errorf("could not add watch to directory: %w", err)
|
||||||
}
|
}
|
||||||
newDir = filepath.Join(string(*w.selected), "cur")
|
newDir = filepath.Join(string(*w.selected), "cur")
|
||||||
if err := w.watcher.Add(newDir); err != nil {
|
if err := w.watcher.Add(newDir); err != nil {
|
||||||
return fmt.Errorf("could not add watch to directory: %v", err)
|
return fmt.Errorf("could not add watch to directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dir.Clean(); err != nil {
|
if err := dir.Clean(); err != nil {
|
||||||
return fmt.Errorf("could not clean directory: %v", err)
|
return fmt.Errorf("could not clean directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := &types.DirectoryInfo{
|
info := &types.DirectoryInfo{
|
||||||
|
@ -426,13 +426,13 @@ func (w *Worker) handleFetchDirectoryContents(
|
||||||
} else {
|
} else {
|
||||||
uids, err = w.c.UIDs(*w.selected)
|
uids, err = w.c.UIDs(*w.selected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("failed scanning uids: %v", err)
|
logging.Errorf("failed scanning uids: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sortedUids, err := w.sort(uids, msg.SortCriteria)
|
sortedUids, err := w.sort(uids, msg.SortCriteria)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("failed sorting directory: %v", err)
|
logging.Errorf("failed sorting directory: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.currentSortCriteria = msg.SortCriteria
|
w.currentSortCriteria = msg.SortCriteria
|
||||||
|
@ -451,14 +451,14 @@ func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32,
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
info, err := w.msgInfoFromUid(uid)
|
info, err := w.msgInfoFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msgInfos = append(msgInfos, info)
|
msgInfos = append(msgInfos, info)
|
||||||
}
|
}
|
||||||
sortedUids, err := lib.Sort(msgInfos, criteria)
|
sortedUids, err := lib.Sort(msgInfos, criteria)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not sort the messages: %v", err)
|
logging.Errorf("could not sort the messages: %w", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return sortedUids, nil
|
return sortedUids, nil
|
||||||
|
@ -467,7 +467,7 @@ func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32,
|
||||||
func (w *Worker) handleCreateDirectory(msg *types.CreateDirectory) error {
|
func (w *Worker) handleCreateDirectory(msg *types.CreateDirectory) error {
|
||||||
dir := w.c.Dir(msg.Directory)
|
dir := w.c.Dir(msg.Directory)
|
||||||
if err := dir.Init(); err != nil {
|
if err := dir.Init(); err != nil {
|
||||||
logging.Errorf("could not create directory %s: %v",
|
logging.Errorf("could not create directory %s: %w",
|
||||||
msg.Directory, err)
|
msg.Directory, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -477,7 +477,7 @@ func (w *Worker) handleCreateDirectory(msg *types.CreateDirectory) error {
|
||||||
func (w *Worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
|
func (w *Worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
|
||||||
dir := w.c.Dir(msg.Directory)
|
dir := w.c.Dir(msg.Directory)
|
||||||
if err := os.RemoveAll(string(dir)); err != nil {
|
if err := os.RemoveAll(string(dir)); err != nil {
|
||||||
logging.Errorf("could not remove directory %s: %v",
|
logging.Errorf("could not remove directory %s: %w",
|
||||||
msg.Directory, err)
|
msg.Directory, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -490,7 +490,7 @@ func (w *Worker) handleFetchMessageHeaders(
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
info, err := w.msgInfoFromUid(uid)
|
info, err := w.msgInfoFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -509,13 +509,13 @@ func (w *Worker) handleFetchMessageBodyPart(
|
||||||
// get reader
|
// get reader
|
||||||
m, err := w.c.Message(*w.selected, msg.Uid)
|
m, err := w.c.Message(*w.selected, msg.Uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %d: %v", msg.Uid, err)
|
logging.Errorf("could not get message %d: %w", msg.Uid, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r, err := m.NewBodyPartReader(msg.Part)
|
r, err := m.NewBodyPartReader(msg.Part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf(
|
logging.Errorf(
|
||||||
"could not get body part reader for message=%d, parts=%#v: %v",
|
"could not get body part reader for message=%d, parts=%#v: %w",
|
||||||
msg.Uid, msg.Part, err)
|
msg.Uid, msg.Part, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -534,12 +534,12 @@ func (w *Worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.c.Message(*w.selected, uid)
|
m, err := w.c.Message(*w.selected, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %d: %v", uid, err)
|
logging.Errorf("could not get message %d: %w", uid, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r, err := m.NewReader()
|
r, err := m.NewReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message reader: %v", err)
|
logging.Errorf("could not get message reader: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
@ -570,7 +570,7 @@ func (w *Worker) handleDeleteMessages(msg *types.DeleteMessages) error {
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("failed removing messages: %v", err)
|
logging.Errorf("failed removing messages: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -580,18 +580,18 @@ func (w *Worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.c.Message(*w.selected, uid)
|
m, err := w.c.Message(*w.selected, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := m.MarkReplied(msg.Answered); err != nil {
|
if err := m.MarkReplied(msg.Answered); err != nil {
|
||||||
logging.Errorf("could not mark message as answered: %v", err)
|
logging.Errorf("could not mark message as answered: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := m.MessageInfo()
|
info, err := m.MessageInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -612,19 +612,19 @@ func (w *Worker) handleFlagMessages(msg *types.FlagMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.c.Message(*w.selected, uid)
|
m, err := w.c.Message(*w.selected, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
flag := flagToMaildir[msg.Flag]
|
flag := flagToMaildir[msg.Flag]
|
||||||
if err := m.SetOneFlag(flag, msg.Enable); err != nil {
|
if err := m.SetOneFlag(flag, msg.Enable); err != nil {
|
||||||
logging.Errorf("could change flag %v to %v on message: %v", flag, msg.Enable, err)
|
logging.Errorf("could change flag %v to %v on message: %w", flag, msg.Enable, err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := m.MessageInfo()
|
info, err := m.MessageInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -661,12 +661,12 @@ func (w *Worker) handleAppendMessage(msg *types.AppendMessage) error {
|
||||||
dest := w.c.Dir(msg.Destination)
|
dest := w.c.Dir(msg.Destination)
|
||||||
_, writer, err := dest.Create(translateFlags(msg.Flags))
|
_, writer, err := dest.Create(translateFlags(msg.Flags))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not create message at %s: %v", msg.Destination, err)
|
logging.Errorf("could not create message at %s: %w", msg.Destination, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
if _, err := io.Copy(writer, msg.Reader); err != nil {
|
if _, err := io.Copy(writer, msg.Reader); err != nil {
|
||||||
logging.Errorf("could not write message to destination: %v", err)
|
logging.Errorf("could not write message to destination: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.worker.PostMessage(&types.Done{
|
w.worker.PostMessage(&types.Done{
|
||||||
|
@ -729,7 +729,7 @@ func (w *Worker) handleCheckMail(msg *types.CheckMail) {
|
||||||
w.err(msg, fmt.Errorf("checkmail: timed out"))
|
w.err(msg, fmt.Errorf("checkmail: timed out"))
|
||||||
case err := <-ch:
|
case err := <-ch:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.err(msg, fmt.Errorf("checkmail: error running command: %v", err))
|
w.err(msg, fmt.Errorf("checkmail: error running command: %w", err))
|
||||||
} else {
|
} else {
|
||||||
w.done(msg)
|
w.done(msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mboxer
|
package mboxer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
@ -16,7 +17,7 @@ func Read(r io.Reader) ([]lib.RawMessage, error) {
|
||||||
messages := make([]lib.RawMessage, 0)
|
messages := make([]lib.RawMessage, 0)
|
||||||
for {
|
for {
|
||||||
msg, err := mbr.NextMessage()
|
msg, err := mbr.NextMessage()
|
||||||
if err == io.EOF {
|
if errors.Is(err, io.EOF) {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -89,7 +89,7 @@ func (md *mailboxContainer) Copy(dest, src string, uids []uint32) error {
|
||||||
}
|
}
|
||||||
err = destmbox.Append(r, flags)
|
err = destmbox.Append(r, flags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not append data to mbox: %v", err)
|
return fmt.Errorf("could not append data to mbox: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package mboxer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -113,12 +114,12 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
for _, uid := range w.folder.Uids() {
|
for _, uid := range w.folder.Uids() {
|
||||||
m, err := w.folder.Message(uid)
|
m, err := w.folder.Message(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %v", err)
|
logging.Errorf("could not get message %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := lib.MessageInfo(m)
|
info, err := lib.MessageInfo(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info %v", err)
|
logging.Errorf("could not get message info %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
infos = append(infos, info)
|
infos = append(infos, info)
|
||||||
|
@ -176,27 +177,27 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
case *types.FetchMessageBodyPart:
|
case *types.FetchMessageBodyPart:
|
||||||
m, err := w.folder.Message(msg.Uid)
|
m, err := w.folder.Message(msg.Uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %d: %v", msg.Uid, err)
|
logging.Errorf("could not get message %d: %w", msg.Uid, err)
|
||||||
reterr = err
|
reterr = err
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
contentReader, err := m.NewReader()
|
contentReader, err := m.NewReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reterr = fmt.Errorf("could not get message reader: %v", err)
|
reterr = fmt.Errorf("could not get message reader: %w", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fullMsg, err := gomessage.Read(contentReader)
|
fullMsg, err := gomessage.Read(contentReader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reterr = fmt.Errorf("could not read message: %v", err)
|
reterr = fmt.Errorf("could not read message: %w", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := lib.FetchEntityPartReader(fullMsg, msg.Part)
|
r, err := lib.FetchEntityPartReader(fullMsg, msg.Part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf(
|
logging.Errorf(
|
||||||
"could not get body part reader for message=%d, parts=%#v: %v",
|
"could not get body part reader for message=%d, parts=%#v: %w",
|
||||||
msg.Uid, msg.Part, err)
|
msg.Uid, msg.Part, err)
|
||||||
reterr = err
|
reterr = err
|
||||||
break
|
break
|
||||||
|
@ -214,18 +215,18 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.folder.Message(uid)
|
m, err := w.folder.Message(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message for uid %d: %v", uid, err)
|
logging.Errorf("could not get message for uid %d: %w", uid, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r, err := m.NewReader()
|
r, err := m.NewReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message reader: %v", err)
|
logging.Errorf("could not get message reader: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
b, err := ioutil.ReadAll(r)
|
b, err := ioutil.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message reader: %v", err)
|
logging.Errorf("could not get message reader: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
w.worker.PostMessage(&types.FullMessage{
|
w.worker.PostMessage(&types.FullMessage{
|
||||||
|
@ -260,16 +261,16 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.folder.Message(uid)
|
m, err := w.folder.Message(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := m.(*message).SetFlag(msg.Flag, msg.Enable); err != nil {
|
if err := m.(*message).SetFlag(msg.Flag, msg.Enable); err != nil {
|
||||||
logging.Errorf("could change flag %v to %t on message: %v", msg.Flag, msg.Enable, err)
|
logging.Errorf("could change flag %v to %t on message: %w", msg.Flag, msg.Enable, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := lib.MessageInfo(m)
|
info, err := lib.MessageInfo(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +366,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
|
||||||
func (w *mboxWorker) Run() {
|
func (w *mboxWorker) Run() {
|
||||||
for msg := range w.worker.Actions {
|
for msg := range w.worker.Actions {
|
||||||
msg = w.worker.ProcessAction(msg)
|
msg = w.worker.ProcessAction(msg)
|
||||||
if err := w.handleMessage(msg); err == errUnsupported {
|
if err := w.handleMessage(msg); errors.Is(err, errUnsupported) {
|
||||||
w.worker.PostMessage(&types.Unsupported{
|
w.worker.PostMessage(&types.Unsupported{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ func (db *DB) connect(writable bool) error {
|
||||||
var err error
|
var err error
|
||||||
db.db, err = notmuch.Open(db.path, mode)
|
db.db, err = notmuch.Open(db.path, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not connect to notmuch db: %v", err)
|
return fmt.Errorf("could not connect to notmuch db: %w", err)
|
||||||
}
|
}
|
||||||
db.lastOpenTime = time.Now()
|
db.lastOpenTime = time.Now()
|
||||||
return nil
|
return nil
|
||||||
|
@ -112,7 +113,7 @@ func (db *DB) newQuery(ndb *notmuch.DB, query string) (*notmuch.Query, error) {
|
||||||
q.SetSortScheme(notmuch.SORT_OLDEST_FIRST)
|
q.SetSortScheme(notmuch.SORT_OLDEST_FIRST)
|
||||||
for _, t := range db.excludedTags {
|
for _, t := range db.excludedTags {
|
||||||
err := q.AddTagExclude(t)
|
err := q.AddTagExclude(t)
|
||||||
if err != nil && err != notmuch.ErrIgnored {
|
if errors.Is(err, notmuch.ErrIgnored) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (m *Message) NewBodyPartReader(requestedParts []int) (io.Reader, error) {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
msg, err := message.Read(f)
|
msg, err := message.Read(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read message: %v", err)
|
return nil, fmt.Errorf("could not read message: %w", err)
|
||||||
}
|
}
|
||||||
return lib.FetchEntityPartReader(msg, requestedParts)
|
return lib.FetchEntityPartReader(msg, requestedParts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -61,22 +62,22 @@ func (w *worker) Run() {
|
||||||
select {
|
select {
|
||||||
case action := <-w.w.Actions:
|
case action := <-w.w.Actions:
|
||||||
msg := w.w.ProcessAction(action)
|
msg := w.w.ProcessAction(action)
|
||||||
if err := w.handleMessage(msg); err == errUnsupported {
|
if err := w.handleMessage(msg); errors.Is(err, errUnsupported) {
|
||||||
w.w.PostMessage(&types.Unsupported{
|
w.w.PostMessage(&types.Unsupported{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
}, nil)
|
}, nil)
|
||||||
logging.Errorf("ProcessAction(%T) unsupported: %v", msg, err)
|
logging.Errorf("ProcessAction(%T) unsupported: %w", msg, err)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
w.w.PostMessage(&types.Error{
|
w.w.PostMessage(&types.Error{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
Error: err,
|
Error: err,
|
||||||
}, nil)
|
}, nil)
|
||||||
logging.Errorf("ProcessAction(%T) failure: %v", msg, err)
|
logging.Errorf("ProcessAction(%T) failure: %w", msg, err)
|
||||||
}
|
}
|
||||||
case nmEvent := <-w.nmEvents:
|
case nmEvent := <-w.nmEvents:
|
||||||
err := w.handleNotmuchEvent(nmEvent)
|
err := w.handleNotmuchEvent(nmEvent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("notmuch event failure: %v", err)
|
logging.Errorf("notmuch event failure: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,22 +158,22 @@ func (w *worker) handleConfigure(msg *types.Configure) error {
|
||||||
w.setupErr = nil
|
w.setupErr = nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.setupErr = fmt.Errorf("notmuch: %v", err)
|
w.setupErr = fmt.Errorf("notmuch: %w", err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
u, err := url.Parse(msg.Config.Source)
|
u, err := url.Parse(msg.Config.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("error configuring notmuch worker: %v", err)
|
logging.Errorf("error configuring notmuch worker: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
home, err := homedir.Expand(u.Hostname())
|
home, err := homedir.Expand(u.Hostname())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not resolve home directory: %v", err)
|
return fmt.Errorf("could not resolve home directory: %w", err)
|
||||||
}
|
}
|
||||||
pathToDB := filepath.Join(home, u.Path)
|
pathToDB := filepath.Join(home, u.Path)
|
||||||
err = w.loadQueryMap(msg.Config)
|
err = w.loadQueryMap(msg.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not load query map configuration: %v", err)
|
return fmt.Errorf("could not load query map configuration: %w", err)
|
||||||
}
|
}
|
||||||
excludedTags := w.loadExcludeTags(msg.Config)
|
excludedTags := w.loadExcludeTags(msg.Config)
|
||||||
w.db = notmuch.NewDB(pathToDB, excludedTags)
|
w.db = notmuch.NewDB(pathToDB, excludedTags)
|
||||||
|
@ -313,13 +314,13 @@ func (w *worker) handleFetchMessageHeaders(
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = w.emitMessageInfo(m, msg)
|
err = w.emitMessageInfo(m, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not emit message info: %v", err)
|
logging.Errorf("could not emit message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -360,13 +361,13 @@ func (w *worker) handleFetchMessageBodyPart(
|
||||||
) error {
|
) error {
|
||||||
m, err := w.msgFromUid(msg.Uid)
|
m, err := w.msgFromUid(msg.Uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %d: %v", msg.Uid, err)
|
logging.Errorf("could not get message %d: %w", msg.Uid, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r, err := m.NewBodyPartReader(msg.Part)
|
r, err := m.NewBodyPartReader(msg.Part)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf(
|
logging.Errorf(
|
||||||
"could not get body part reader for message=%d, parts=%#v: %v",
|
"could not get body part reader for message=%d, parts=%#v: %w",
|
||||||
msg.Uid, msg.Part, err)
|
msg.Uid, msg.Part, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -386,12 +387,12 @@ func (w *worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message %d: %v", uid, err)
|
logging.Errorf("could not get message %d: %w", uid, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r, err := m.NewReader()
|
r, err := m.NewReader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message reader: %v", err)
|
logging.Errorf("could not get message reader: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
@ -415,24 +416,24 @@ func (w *worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := m.MarkAnswered(msg.Answered); err != nil {
|
if err := m.MarkAnswered(msg.Answered); err != nil {
|
||||||
logging.Errorf("could not mark message as answered: %v", err)
|
logging.Errorf("could not mark message as answered: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = w.emitMessageInfo(m, msg)
|
err = w.emitMessageInfo(m, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not emit message info: %v", err)
|
logging.Errorf("could not emit message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
if err := w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
||||||
logging.Errorf("could not emit directory info: %v", err)
|
logging.Errorf("could not emit directory info: %w", err)
|
||||||
}
|
}
|
||||||
w.done(msg)
|
w.done(msg)
|
||||||
return nil
|
return nil
|
||||||
|
@ -442,24 +443,24 @@ func (w *worker) handleFlagMessages(msg *types.FlagMessages) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := m.SetFlag(msg.Flag, msg.Enable); err != nil {
|
if err := m.SetFlag(msg.Flag, msg.Enable); err != nil {
|
||||||
logging.Errorf("could not set flag %v as %t for message: %v", msg.Flag, msg.Enable, err)
|
logging.Errorf("could not set flag %v as %t for message: %w", msg.Flag, msg.Enable, err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = w.emitMessageInfo(m, msg)
|
err = w.emitMessageInfo(m, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not emit message info: %v", err)
|
logging.Errorf("could not emit message info: %w", err)
|
||||||
w.err(msg, err)
|
w.err(msg, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
if err := w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
||||||
logging.Errorf("could not emit directory info: %v", err)
|
logging.Errorf("could not emit directory info: %w", err)
|
||||||
}
|
}
|
||||||
w.done(msg)
|
w.done(msg)
|
||||||
return nil
|
return nil
|
||||||
|
@ -488,11 +489,11 @@ func (w *worker) handleModifyLabels(msg *types.ModifyLabels) error {
|
||||||
for _, uid := range msg.Uids {
|
for _, uid := range msg.Uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get message from uid %d: %v", uid, err)
|
return fmt.Errorf("could not get message from uid %d: %w", uid, err)
|
||||||
}
|
}
|
||||||
err = m.ModifyTags(msg.Add, msg.Remove)
|
err = m.ModifyTags(msg.Add, msg.Remove)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not modify message tags: %v", err)
|
return fmt.Errorf("could not modify message tags: %w", err)
|
||||||
}
|
}
|
||||||
err = w.emitMessageInfo(m, msg)
|
err = w.emitMessageInfo(m, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -508,7 +509,7 @@ func (w *worker) handleModifyLabels(msg *types.ModifyLabels) error {
|
||||||
// and update the list of possible tags
|
// and update the list of possible tags
|
||||||
w.emitLabelList()
|
w.emitLabelList()
|
||||||
if err = w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
if err = w.emitDirectoryInfo(w.currentQueryName); err != nil {
|
||||||
logging.Errorf("could not emit directory info: %v", err)
|
logging.Errorf("could not emit directory info: %w", err)
|
||||||
}
|
}
|
||||||
w.done(msg)
|
w.done(msg)
|
||||||
return nil
|
return nil
|
||||||
|
@ -572,11 +573,11 @@ func (w *worker) emitDirectoryContents(parent types.WorkerMessage) error {
|
||||||
}
|
}
|
||||||
uids, err := w.uidsFromQuery(query)
|
uids, err := w.uidsFromQuery(query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not fetch uids: %v", err)
|
return fmt.Errorf("could not fetch uids: %w", err)
|
||||||
}
|
}
|
||||||
sortedUids, err := w.sort(uids, w.currentSortCriteria)
|
sortedUids, err := w.sort(uids, w.currentSortCriteria)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("error sorting directory: %v", err)
|
logging.Errorf("error sorting directory: %w", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.w.PostMessage(&types.DirectoryContents{
|
w.w.PostMessage(&types.DirectoryContents{
|
||||||
|
@ -609,7 +610,7 @@ func (w *worker) emitMessageInfo(m *Message,
|
||||||
) error {
|
) error {
|
||||||
info, err := m.MessageInfo()
|
info, err := m.MessageInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get MessageInfo: %v", err)
|
return fmt.Errorf("could not get MessageInfo: %w", err)
|
||||||
}
|
}
|
||||||
w.w.PostMessage(&types.MessageInfo{
|
w.w.PostMessage(&types.MessageInfo{
|
||||||
Message: types.RespondTo(parent),
|
Message: types.RespondTo(parent),
|
||||||
|
@ -621,7 +622,7 @@ func (w *worker) emitMessageInfo(m *Message,
|
||||||
func (w *worker) emitLabelList() {
|
func (w *worker) emitLabelList() {
|
||||||
tags, err := w.db.ListTags()
|
tags, err := w.db.ListTags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not load tags: %v", err)
|
logging.Errorf("could not load tags: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.w.PostMessage(&types.LabelList{Labels: tags}, nil)
|
w.w.PostMessage(&types.LabelList{Labels: tags}, nil)
|
||||||
|
@ -637,19 +638,19 @@ func (w *worker) sort(uids []uint32,
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
m, err := w.msgFromUid(uid)
|
m, err := w.msgFromUid(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message: %v", err)
|
logging.Errorf("could not get message: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := m.MessageInfo()
|
info, err := m.MessageInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not get message info: %v", err)
|
logging.Errorf("could not get message info: %w", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
msgInfos = append(msgInfos, info)
|
msgInfos = append(msgInfos, info)
|
||||||
}
|
}
|
||||||
sortedUids, err := lib.Sort(msgInfos, criteria)
|
sortedUids, err := lib.Sort(msgInfos, criteria)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Errorf("could not sort the messages: %v", err)
|
logging.Errorf("could not sort the messages: %w", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return sortedUids, nil
|
return sortedUids, nil
|
||||||
|
@ -673,7 +674,7 @@ func (w *worker) handleCheckMail(msg *types.CheckMail) {
|
||||||
w.err(msg, fmt.Errorf("checkmail: timed out"))
|
w.err(msg, fmt.Errorf("checkmail: timed out"))
|
||||||
case err := <-ch:
|
case err := <-ch:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.err(msg, fmt.Errorf("checkmail: error running command: %v", err))
|
w.err(msg, fmt.Errorf("checkmail: error running command: %w", err))
|
||||||
} else {
|
} else {
|
||||||
w.done(msg)
|
w.done(msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ func (t *Thread) insertCmp(child *Thread, cmp func(*Thread, *Thread) bool) {
|
||||||
|
|
||||||
func (t *Thread) Walk(walkFn NewThreadWalkFn) error {
|
func (t *Thread) Walk(walkFn NewThreadWalkFn) error {
|
||||||
err := newWalk(t, walkFn, 0, nil)
|
err := newWalk(t, walkFn, 0, nil)
|
||||||
if err == ErrSkipThread {
|
if errors.Is(err, ErrSkipThread) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -80,7 +80,7 @@ func newWalk(node *Thread, walkFn NewThreadWalkFn, lvl int, ce error) error {
|
||||||
}
|
}
|
||||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||||
err = newWalk(child, walkFn, lvl+1, err)
|
err = newWalk(child, walkFn, lvl+1, err)
|
||||||
if err == ErrSkipThread {
|
if errors.Is(err, ErrSkipThread) {
|
||||||
err = nil
|
err = nil
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue