mirror of
				https://git.sr.ht/~rjarry/aerc
				synced 2025-11-04 15:52:35 +01:00 
			
		
		
		
	The maildir backend was ignoring the passed/forwarded flag. Allow for this flag to be set and synced to the server (if the server admits it). Changelog-added: The maildir backend now honors the forwarded/passed flag. Signed-off-by: inwit <inwit@sindominio.net> Acked-by: Robin Jarry <robin@jarry.cc>
		
			
				
	
	
		
			152 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package lib
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"regexp"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"git.sr.ht/~rjarry/aerc/models"
 | 
						|
	"github.com/emersion/go-maildir"
 | 
						|
)
 | 
						|
 | 
						|
type MaildirStore struct {
 | 
						|
	root      string
 | 
						|
	maildirpp bool // whether to use Maildir++ directory layout
 | 
						|
}
 | 
						|
 | 
						|
func NewMaildirStore(root string, maildirpp bool) (*MaildirStore, error) {
 | 
						|
	f, err := os.Open(root)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
	s, err := f.Stat()
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if !s.IsDir() {
 | 
						|
		return nil, fmt.Errorf("Given maildir '%s' not a directory", root)
 | 
						|
	}
 | 
						|
	return &MaildirStore{
 | 
						|
		root: root, maildirpp: maildirpp,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (s *MaildirStore) FolderMap() (map[string]maildir.Dir, error) {
 | 
						|
	folders := make(map[string]maildir.Dir)
 | 
						|
	if s.maildirpp {
 | 
						|
		// In Maildir++ layout, INBOX is the root folder
 | 
						|
		folders["INBOX"] = maildir.Dir(s.root)
 | 
						|
	}
 | 
						|
	err := filepath.Walk(s.root, func(path string, info os.FileInfo, err error) error {
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("Invalid path '%s': error: %w", path, err)
 | 
						|
		}
 | 
						|
		if !info.IsDir() {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		// Skip maildir's default directories
 | 
						|
		n := info.Name()
 | 
						|
		if n == "new" || n == "tmp" || n == "cur" {
 | 
						|
			return filepath.SkipDir
 | 
						|
		}
 | 
						|
 | 
						|
		// Get the relative path from the parent directory
 | 
						|
		dirPath, err := filepath.Rel(s.root, path)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		// Skip the parent directory
 | 
						|
		if dirPath == "." {
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
 | 
						|
		// Drop dirs that lack {new,tmp,cur} subdirs
 | 
						|
		for _, sub := range []string{"new", "tmp", "cur"} {
 | 
						|
			if _, err := os.Stat(filepath.Join(path, sub)); os.IsNotExist(err) {
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if s.maildirpp {
 | 
						|
			// In Maildir++ layout, mailboxes are stored in a single directory
 | 
						|
			// and prefixed with a dot, and subfolders are separated by dots.
 | 
						|
			if !strings.HasPrefix(dirPath, ".") {
 | 
						|
				return filepath.SkipDir
 | 
						|
			}
 | 
						|
			dirPath = strings.TrimPrefix(dirPath, ".")
 | 
						|
			dirPath = strings.ReplaceAll(dirPath, ".", "/")
 | 
						|
			folders[dirPath] = maildir.Dir(path)
 | 
						|
 | 
						|
			// Since all mailboxes are stored in a single directory, don't
 | 
						|
			// recurse into subdirectories
 | 
						|
			return filepath.SkipDir
 | 
						|
		}
 | 
						|
 | 
						|
		folders[dirPath] = maildir.Dir(path)
 | 
						|
		return nil
 | 
						|
	})
 | 
						|
	return folders, err
 | 
						|
}
 | 
						|
 | 
						|
// Folder returns a maildir.Dir with the specified name inside the Store
 | 
						|
func (s *MaildirStore) Dir(name string) maildir.Dir {
 | 
						|
	if s.maildirpp {
 | 
						|
		// Use Maildir++ layout
 | 
						|
		if name == "INBOX" {
 | 
						|
			return maildir.Dir(s.root)
 | 
						|
		}
 | 
						|
		return maildir.Dir(filepath.Join(s.root, "."+strings.ReplaceAll(name, "/", ".")))
 | 
						|
	}
 | 
						|
	return maildir.Dir(filepath.Join(s.root, name))
 | 
						|
}
 | 
						|
 | 
						|
// uidReg matches filename encoded UIDs in maildirs synched with mbsync or
 | 
						|
// OfflineIMAP
 | 
						|
var uidReg = regexp.MustCompile(`,U=\d+`)
 | 
						|
 | 
						|
func StripUIDFromMessageFilename(basename string) string {
 | 
						|
	return uidReg.ReplaceAllString(basename, "")
 | 
						|
}
 | 
						|
 | 
						|
var MaildirToFlag = map[maildir.Flag]models.Flags{
 | 
						|
	maildir.FlagReplied: models.AnsweredFlag,
 | 
						|
	maildir.FlagSeen:    models.SeenFlag,
 | 
						|
	maildir.FlagTrashed: models.DeletedFlag,
 | 
						|
	maildir.FlagFlagged: models.FlaggedFlag,
 | 
						|
	maildir.FlagDraft:   models.DraftFlag,
 | 
						|
	maildir.FlagPassed:  models.ForwardedFlag,
 | 
						|
}
 | 
						|
 | 
						|
var FlagToMaildir = map[models.Flags]maildir.Flag{
 | 
						|
	models.AnsweredFlag:  maildir.FlagReplied,
 | 
						|
	models.SeenFlag:      maildir.FlagSeen,
 | 
						|
	models.DeletedFlag:   maildir.FlagTrashed,
 | 
						|
	models.FlaggedFlag:   maildir.FlagFlagged,
 | 
						|
	models.DraftFlag:     maildir.FlagDraft,
 | 
						|
	models.ForwardedFlag: maildir.FlagPassed,
 | 
						|
}
 | 
						|
 | 
						|
func FromMaildirFlags(maildirFlags []maildir.Flag) models.Flags {
 | 
						|
	var flags models.Flags
 | 
						|
	for _, maildirFlag := range maildirFlags {
 | 
						|
		if flag, ok := MaildirToFlag[maildirFlag]; ok {
 | 
						|
			flags |= flag
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return flags
 | 
						|
}
 | 
						|
 | 
						|
func ToMaildirFlags(flags models.Flags) []maildir.Flag {
 | 
						|
	var maildirFlags []maildir.Flag
 | 
						|
	for flag, maildirFlag := range FlagToMaildir {
 | 
						|
		if flags.Has(flag) {
 | 
						|
			maildirFlags = append(maildirFlags, maildirFlag)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return maildirFlags
 | 
						|
}
 |