about summary refs log blame commit diff stats
path: root/cpp/.traces/convert_names_passes_dummy
blob: c836a7aa00f5cb7a9e9dca1d9c5edd19c4f0aa90 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                                                               
                                                                          





                                                                            
parse/0: instruction: 1
parse/0:   ingredient: {name: "0", value: 0, type: 0, properties: [0: literal]}
parse/0:   product: {name: "_", value: 0, type: 0, properties: [_: dummy]}
parse/0:   product: {name: "x", value: 0, type: 1, properties: [x: integer]}
name/0: assign x 1
after-brace/0: recipe main
after-brace/0: copy ...
run/0: instruction main/0
run/0: ingredient 0 is 0
tring.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
package maildir

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"path/filepath"
	"sort"

	"github.com/emersion/go-maildir"

	"git.sr.ht/~sircmpwn/aerc/lib/uidstore"
)

// A Container is a directory which contains other directories which adhere to
// the Maildir spec
type Container struct {
	dir  string
	log  *log.Logger
	uids *uidstore.Store
}

// NewContainer creates a new container at the specified directory
// TODO: return an error if the provided directory is not accessible
func NewContainer(dir string, l *log.Logger) *Container {
	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}
}

// ListFolders returns a list of maildir folders in the container
func (c *Container) ListFolders() ([]string, error) {
	files, err := ioutil.ReadDir(c.dir)
	if err != nil {
		return nil, fmt.Errorf("error reading folders: %v", err)
	}
	dirnames := []string{}
	for _, f := range files {
		if f.IsDir() {
			dirnames = append(dirnames, f.Name())
		}
	}
	return dirnames, nil
}

// OpenDirectory opens an existing maildir in the container by name, moves new
// messages into cur, and registers the new keys in the UIDStore.
func (c *Container) OpenDirectory(name string) (maildir.Dir, error) {
	dir := c.Dir(name)
	keys, err := dir.Unseen()
	if err != nil {
		return dir, err
	}
	for _, key := range keys {
		c.uids.GetOrInsert(key)
	}
	return dir, nil
}

// Dir returns a maildir.Dir with the specified name inside the container
func (c *Container) Dir(name string) maildir.Dir {
	return maildir.Dir(filepath.Join(c.dir, name))
}

// UIDs fetches the unique message identifiers for the maildir
func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
	keys, err := d.Keys()
	if err != nil {
		return nil, fmt.Errorf("could not get keys for %s: %v", d, err)
	}
	sort.Strings(keys)
	var uids []uint32
	for _, key := range keys {
		uids = append(uids, c.uids.GetOrInsert(key))
	}
	return uids, nil
}

// Message returns a Message struct for the given UID and maildir
func (c *Container) Message(d maildir.Dir, uid uint32) (*Message, error) {
	if key, ok := c.uids.GetKey(uid); ok {
		return &Message{
			dir: d,
			uid: uid,
			key: key,
		}, nil
	}
	return nil, fmt.Errorf("could not find message with uid %d in maildir %s",
		uid, d)
}

// DeleteAll deletes a set of messages by UID and returns the subset of UIDs
// which were successfully deleted, stopping upon the first error.
func (c *Container) DeleteAll(d maildir.Dir, uids []uint32) ([]uint32, error) {
	var success []uint32
	for _, uid := range uids {
		msg, err := c.Message(d, uid)
		if err != nil {
			return success, err
		}
		if err := msg.Remove(); err != nil {
			return success, err
		}
		success = append(success, uid)
	}
	return success, nil
}

func (c *Container) CopyAll(
	dest maildir.Dir, src maildir.Dir, uids []uint32) error {
	for _, uid := range uids {
		if err := c.copyMessage(dest, src, uid); err != nil {
			return fmt.Errorf("could not copy message %d: %v", uid, err)
		}
	}
	return nil
}

func (c *Container) copyMessage(
	dest maildir.Dir, src maildir.Dir, uid uint32) error {
	key, ok := c.uids.GetKey(uid)
	if !ok {
		return fmt.Errorf("could not find key for message id %d", uid)
	}

	f, err := src.Open(key)
	if err != nil {
		return fmt.Errorf("could not open source message: %v", err)
	}

	del, err := dest.NewDelivery()
	if err != nil {
		return fmt.Errorf("could not initialize delivery: %v")
	}
	defer del.Close()

	if _, err = io.Copy(del, f); err != nil {
		return fmt.Errorf("could not copy message to delivery: %v")
	}

	// TODO: preserve flags

	return nil
}