about summary refs log tree commit diff stats
path: root/mu.arc
Commit message (Expand)AuthorAgeFilesLines
...
* 607Kartik K. Agaram2015-01-241-3/+9
* 605 - example program for line-oriented inputKartik K. Agaram2015-01-241-2/+15
* 604 - new function to buffer stdinKartik K. Agaram2015-01-241-5/+57
* 603Kartik K. Agaram2015-01-241-9/+12
* 602Kartik K. Agaram2015-01-241-6/+9
* 601 - fix callers of 'read-key'Kartik K. Agaram2015-01-241-1/+2
* 600 - fake keyboardKartik K. Agaram2015-01-221-6/+30
* 598 - clear up a minor mysteryKartik K. Agaram2015-01-211-4/+5
* 597Kartik K. Agaram2015-01-211-8/+0
* 595 - tests can now interrupt and restart routinesKartik K. Agaram2015-01-211-71/+37
* 594 - random snapshot after a lengthy debugKartik K. Agaram2015-01-211-13/+80
* 588Kartik K. Agaram2015-01-181-0/+2
* 582 - first tests for printing to screenKartik K. Agaram2015-01-171-6/+68
* 580Kartik K. Agaram2015-01-171-1/+1
* 578 - switch to non-polymorphic 'print' functionsKartik K. Agaram2015-01-171-43/+78
* 577 - bounds-check on per-routine spaceKartik K. Agaram2015-01-171-7/+19
* 576 - helper for printing integersKartik K. Agaram2015-01-171-0/+125
* 575Kartik K. Agaram2015-01-171-14/+12
* 574 - printing string literals is a hack; hard-code it in for nowKartik K. Agaram2015-01-161-24/+24
* 571 - screen primitives take an explicit terminalKartik K. Agaram2015-01-151-40/+64
* 570 - warn on potential name conflictKartik K. Agaram2015-01-141-0/+2
* 569 - ah, the right way to do generic functionsKartik K. Agaram2015-01-141-1/+4
* 568Kartik K. Agaram2015-01-141-0/+3
* 566Kartik K. Agaram2015-01-141-4/+25
* 565Kartik K. Agaram2015-01-141-10/+4
* 563 - check actual errors during move validationKartik K. Agaram2015-01-141-2/+5
* 559Kartik K. Agaram2015-01-131-1/+0
* 554 - tedious to have to check for routine errors on every forkKartik K. Agaram2015-01-131-1/+1
* 550 - another bugfix, another pending testKartik K. Agaram2015-01-131-0/+4
* 549 - suppress prints in read-moveKartik K. Agaram2015-01-131-1/+11
* 545 - graphics mode is now called bringing up a windowKartik K. Agaram2015-01-121-2/+2
* 544 - text modes now called 'retro' & 'cursor'Kartik K. Agaram2015-01-121-2/+2
* 542Kartik K. Agaram2015-01-121-3/+23
* 541Kartik K. Agaram2015-01-111-3/+3
* 540Kartik K. Agaram2015-01-111-1/+1
* 539Kartik K. Agaram2015-01-111-6/+3
* 538 - stdin app now responsiveKartik K. Agaram2015-01-111-1/+6
* 537Kartik K. Agaram2015-01-111-5/+0
* 536 - introduce a notion of helper routinesKartik K. Agaram2015-01-111-1/+16
* 535 - reading keyboard input from a channelKartik K. Agaram2015-01-111-2/+23
* 534 - this is how we test blocking channelsKartik K. Agaram2015-01-111-4/+2
* 533Kartik K. Agaram2015-01-111-1/+3
* 532Kartik K. Agaram2015-01-111-4/+6
* 531Kartik K. Agaram2015-01-101-1/+1
* 530Kartik K. Agaram2015-01-101-1/+3
* 529 - 'sleep' can now wait for a routine to completeKartik K. Agaram2015-01-101-0/+5
* 528Kartik K. Agaram2015-01-101-3/+3
* 527Kartik K. Agaram2015-01-101-3/+3
* 526Kartik K. Agaram2015-01-101-2/+0
* 525 - 'fork' now returns a routine idKartik K. Agaram2015-01-101-3/+5
8800; 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 compose

import (
	"io"
	"io/ioutil"
	"time"

	"github.com/miolini/datacounter"
	"github.com/pkg/errors"

	"git.sr.ht/~sircmpwn/aerc/models"
	"git.sr.ht/~sircmpwn/aerc/widgets"
	"git.sr.ht/~sircmpwn/aerc/worker/types"
)

type Postpone struct{}

func init() {
	register(Postpone{})
}

func (Postpone) Aliases() []string {
	return []string{"postpone"}
}

func (Postpone) Complete(aerc *widgets.Aerc, args []string) []string {
	return nil
}

func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
	if len(args) != 1 {
		return errors.New("Usage: postpone")
	}
	composer, _ := aerc.SelectedTab().(*widgets.Composer)
	config := composer.Config()

	if config.Postpone == "" {
		return errors.New("No Postpone location configured")
	}

	aerc.Logger().Println("Postponing mail")

	header, _, err := composer.PrepareHeader()
	if err != nil {
		return errors.Wrap(err, "PrepareHeader")
	}
	header.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
	header.Set("Content-Transfer-Encoding", "quoted-printable")
	worker := composer.Worker()
	dirs := aerc.SelectedAccount().Directories().List()
	alreadyCreated := false
	for _, dir := range dirs {
		if dir == config.Postpone {
			alreadyCreated = true
			break
		}
	}

	errChan := make(chan string)

	// run this as a goroutine so we can make other progress. The message
	// will be saved once the directory is created.
	go func() {
		errStr := <-errChan
		if errStr != "" {
			aerc.PushError(" "+errStr, 10*time.Second)
			return
		}

		aerc.RemoveTab(composer)
		ctr := datacounter.NewWriterCounter(ioutil.Discard)
		err = composer.WriteMessage(header, ctr)
		if err != nil {
			aerc.PushError(errors.Wrap(err, "WriteMessage").Error(), 10*time.Second)
			composer.Close()
			return
		}
		nbytes := int(ctr.Count())
		r, w := io.Pipe()
		worker.PostAction(&types.AppendMessage{
			Destination: config.Postpone,
			Flags:       []models.Flag{models.SeenFlag},
			Date:        time.Now(),
			Reader:      r,
			Length:      int(nbytes),
		}, func(msg types.WorkerMessage) {
			switch msg := msg.(type) {
			case *types.Done:
				aerc.PushStatus("Message postponed.", 10*time.Second)
				r.Close()
				composer.Close()
			case *types.Error:
				aerc.PushError(" "+msg.Error.Error(), 10*time.Second)
				r.Close()
				composer.Close()
			}
		})
		composer.WriteMessage(header, w)
		w.Close()
	}()

	if !alreadyCreated {
		// to synchronise the creating of the directory
		worker.PostAction(&types.CreateDirectory{
			Directory: config.Postpone,
		}, func(msg types.WorkerMessage) {
			switch msg := msg.(type) {
			case *types.Done:
				errChan <- ""
			case *types.Error:
				errChan <- msg.Error.Error()
			}
		})
	} else {
		errChan <- ""
	}

	return nil
}