func (mw *MessageWriter) Statusf(fmtspec string, args ...interface{}) {
	mw.Status(fmt.Sprintf(fmtspec, args...))
}
Statusf writes a '102 status' message and formats the arguments into if.
package apt
import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
)
type CapFlags int
const (
	CapSingleInstance CapFlags = 0x01
	CapPipeline CapFlags = 0x02
	CapSendConfig CapFlags = 0x04
	CapLocalOnly CapFlags = 0x08
	CapNeedsCleanup CapFlags = 0x10
	CapRemovable CapFlags = 0x20
	CapAuxRequests CapFlags = 0x40
)
type Message struct {
	StatusCode  uint64
	Description string
	Fields      map[string]string
}
type Field struct {
	Key   string
	Value string
}
func NewMessage(statusCode uint64, description string, fields ...Field) *Message {
	fieldmap := make(map[string]string)
	for _, field := range fields {
		fieldmap[field.Key] = field.Value
	}
	return &Message{
		statusCode,
		description,
		fieldmap,
	}
}
type MessageReader struct {
	reader  *bufio.Reader
	message *Message
}
func NewMessageReader(reader *bufio.Reader) *MessageReader {
	return &MessageReader{
		reader,
		nil,
	}
}
func errorGroup(header string, errs []error) error {
	var sb strings.Builder
	sb.WriteString(header)
	for _, e := range errs {
		sb.WriteString("\n  ")
		sb.WriteString(e.Error())
	}
	return errors.New(sb.String())
}
func (r *MessageReader) ReadMessage() (*Message, error) {
	var errs []error
	var err error
	var msg *Message
	for msg == nil {
		msg, err = r.ReadLine()
		if err != nil {
			if msg != nil || err == io.EOF {
				if len(errs) > 0 {
					errs = append(errs, err)
					return msg, errorGroup("Errors while reading message:", errs)
				}
				return msg, err
			}
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		return msg, errorGroup("Errors while reading message:", errs)
	}
	return msg, nil
}
func (r *MessageReader) ReadLine() (*Message, error) {
	if r.message == nil {
		msg, err := r.readHeader()
		if err != nil {
			return nil, err
		}
		r.message = msg
		return nil, nil
	}
	line, err := r.reader.ReadString('\n')
	if err != nil {
		return r.commitMessage(nil), err
	}
	line = strings.TrimSpace(line)
	if line == "" {
		return r.commitMessage(nil), nil
	}
	parts := strings.SplitN(line, ":", 2)
	if len(parts) != 2 {
		msg, err := ParseHeader(line)
		if err != nil {
			return nil, fmt.Errorf("invalid field format in \"%s\"", line)
		}
		return r.commitMessage(msg), errors.New("new message started without old message ending")
	}
	key := strings.TrimSpace(parts[0])
	value := strings.TrimSpace(parts[1])
	r.message.Fields[key] = value
	return nil, nil
}
func (r *MessageReader) readHeader() (*Message, error) {
	line, err := r.reader.ReadString('\n')
	if err != nil {
		return nil, err
	}
	return ParseHeader(line)
}
func ParseHeader(line string) (*Message, error) {
	line = strings.TrimSpace(line)
	if line == "" {
		return nil, errors.New("not a header spec: Empty line")
	}
	parts := strings.SplitN(line, " ", 2)
	if len(parts) != 2 {
		return nil, fmt.Errorf("not a header spec: \"%s\"", line)
	}
	codeStr := strings.TrimSpace(parts[0])
	code, err := strconv.ParseUint(codeStr, 10, 64)
	if err != nil {
		return nil, fmt.Errorf("could not parse Status Code: %v", err)
	}
	desc := strings.TrimSpace(parts[1])
	if desc == "" {
		return nil, fmt.Errorf("empty description header for \"%s\"", line)
	}
	msg := &Message{
		StatusCode:  code,
		Description: desc,
		Fields:      make(map[string]string),
	}
	return msg, nil
}
func (r *MessageReader) commitMessage(newmsg *Message) *Message {
	msg := r.message
	r.message = newmsg
	return msg
}
type MessageWriter struct {
	w io.Writer
}
func NewMessageWriter(w io.Writer) *MessageWriter {
	return &MessageWriter{w}
}
func (mw *MessageWriter) WriteMessage(msg *Message) {
	fmt.Fprintf(mw.w, "%d %s\n", msg.StatusCode, msg.Description)
	for k, v := range msg.Fields {
		if k != "" && v != "" {
			fmt.Fprintf(mw.w, "%s: %s\n", k, v)
		}
	}
	mw.w.Write([]byte("\n"))
}
func (mw *MessageWriter) Capabilities(version string, caps CapFlags) {
	fmt.Fprintf(mw.w, "100 Capabilities\nVersion: %s\n", version)
	if caps&CapSendConfig != 0 {
		mw.w.Write([]byte("Send-Config: true\n"))
	}
	if caps&CapPipeline != 0 {
		mw.w.Write([]byte("Pipeline: true\n"))
	}
	if caps&CapSingleInstance != 0 {
		mw.w.Write([]byte("Single-Instance: true\n"))
	}
	if caps&CapLocalOnly != 0 {
		mw.w.Write([]byte("Local-Only: true\n"))
	}
	if caps&CapNeedsCleanup != 0 {
		mw.w.Write([]byte("Needs-Cleanup: true\n"))
	}
	if caps&CapRemovable != 0 {
		mw.w.Write([]byte("Removable: true\n"))
	}
	if caps&CapAuxRequests != 0 {
		mw.w.Write([]byte("AuxRequests: true\n"))
	}
	mw.w.Write([]byte("\n"))
}
func (mw *MessageWriter) Log(msg string) {
	fmt.Fprintf(mw.w, "101 Log\nMessage: %s\n\n", msg)
}
func (mw *MessageWriter) Logf(fmtspec string, args ...interface{}) {
	mw.Log(fmt.Sprintf(fmtspec, args...))
}
func (mw *MessageWriter) Status(msg string) {
	fmt.Fprintf(mw.w, "102 Status\nMessage: %s\n\n", msg)
}