Пример #1
0
func switchToMode(amua *Amua, g *gocui.Gui, mode Mode) error {
	/* highlight off */
	if amua.mode.IsHighlighted() {
		v := modeToView(g, amua.mode)
		v.Highlight = false
	}
	amua.prevMode = amua.mode
	amua.mode = mode
	curview := modeToViewStr(amua.mode)
	var err error
	switch amua.mode {
	case MessageMode:
		m := amua.curMessage()
		m.Flags |= Seen
		err = m.Draw(amua, g)
	case MessageMimeMode:
		m := amua.curMessage()
		err = (*MessageAsMimeTree)(m).Draw(amua, g)
	case MaildirMode:
		v, _ := g.View(curview)
		err = amua.curMaildirView.Draw(v)
	case SendMailMode:
		v, _ := g.View(curview)
		err = amua.sendMailDraw(v)
	case CommandNewMailMode:
		tos := util.ConcatAddresses(amua.newMail.to)
		amua.newMail.to = []*mail.Address{}
		displayPromptWithPrefill(TO_PROMPT, tos)
	case CommandMailModeTo:
		displayPromptWithPrefill(TO_PROMPT, util.ConcatAddresses(amua.newMail.to))
	case CommandMailModeCc:
		displayPromptWithPrefill(CC_PROMPT, util.ConcatAddresses(amua.newMail.cc))
	case CommandMailModeBcc:
		displayPromptWithPrefill(BCC_PROMPT, util.ConcatAddresses(amua.newMail.bcc))
	case CommandSearchMode:
		displayPrompt(SEARCH_PROMPT)
	}

	if err != nil {
		v, _ := g.View(curview)
		if v != nil {
			fmt.Fprintf(v, err.Error())
		}
		/* we printed the error, fallback */
	}
	_, err = g.SetViewOnTop(curview)
	if err != nil {
		return err
	}
	err = g.SetCurrentView(curview)
	if err != nil {
		return err
	}
	/* highlight back */
	if amua.mode.IsHighlighted() {
		v := modeToView(g, amua.mode)
		v.Highlight = true
	}
	return nil
}
Пример #2
0
func (m *MessageAsText) Draw(amua *Amua, g *gocui.Gui) error {
	v, err := g.View(MESSAGE_VIEW)
	if err != nil {
		return err
	}
	v.Clear()
	v.Wrap = true
	v.SetOrigin(0, 0)

	_, err = io.Copy(v, m)
	if err != nil {
		return err
	}
	return nil

}
Пример #3
0
func (m *Message) Draw(amua *Amua, g *gocui.Gui) error {
	v, err := g.View(MESSAGE_VIEW)
	if err != nil {
		return err
	}
	v.Clear()
	v.Wrap = true
	v.SetOrigin(0, 0)

	colorstring.Fprintf(v, "[green]Subject: %s\n", m.Subject)
	colorstring.Fprintf(v, "[red]From: %s\n", m.From)
	colorstring.Fprintf(v, "[red]To: %s\n", m.To)
	colorstring.Fprintf(v, "[green]Date: %s\n", m.Date.Format("Mon, 2 Jan 2006 15:04:05 -0700"))
	fmt.Fprintf(v, "\n")
	_, err = io.Copy(v, m)
	if err != nil {
		return err
	}
	return nil

}
Пример #4
0
func drawSlider(amua *Amua, g *gocui.Gui) {
	v, err := g.View(SLIDER_VIEW)
	if err != nil {
		return
	}
	v.Clear()
	_, h := v.Size()
	sliderH := 1
	whites := h - 1
	if len(amua.curMaildirView.md.messages) > 0 {
		sliderH = h * h / len(amua.curMaildirView.md.messages)
		whites = amua.curMaildirView.curTop * h / len(amua.curMaildirView.md.messages)
	}
	if sliderH <= 0 {
		sliderH = 1
	}
	for i := 0; i < whites; i++ {
		fmt.Fprintln(v, " ")
	}
	for i := 0; i < sliderH; i++ {
		fmt.Fprintln(v, "\u2588")
	}
}
Пример #5
0
func keybindings(amua *Amua, g *gocui.Gui) error {
	switchToModeInt := func(mode Mode) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			return switchToMode(amua, g, mode)
		}
	}

	maildirMove := func(dy int) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			amua.curMaildirView.scroll(v, dy)
			drawSlider(amua, g)
			return nil
		}
	}
	maildirAllDown := func() func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			dy := len(amua.curMaildirView.md.messages) - amua.curMaildirView.cur - 1
			amua.curMaildirView.scroll(v, dy)
			drawSlider(amua, g)
			return nil
		}
	}
	messageModeToggle := func(g *gocui.Gui, v *gocui.View) error {
		switch amua.mode {
		case MessageMode:
			switchToMode(amua, g, MessageMimeMode)
		case MessageMimeMode:
			switchToMode(amua, g, MessageMode)
		}
		return nil
	}
	search := func(forward bool) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			setStatus("Looking for: " + amua.searchPattern + " in " + amua.curMaildirView.md.path)
			found := false
			direction := 1
			if forward == false {
				direction = -1
			}
			for i := 0; i < len(amua.curMaildirView.md.messages); i++ {
				idx := ((direction * i) + amua.curMaildirView.cur + direction) % len(amua.curMaildirView.md.messages)
				if idx < 0 {
					idx = len(amua.curMaildirView.md.messages) + idx
				}
				if idx < 0 {
					panic(idx)
				}
				m := amua.getMessage(idx)
				if strings.Contains(m.Subject, amua.searchPattern) {
					setStatus("Found: " + amua.searchPattern + " in " + amua.curMaildirView.md.path)
					found = true
					amua.curMaildirView.curTop = idx
					amua.curMaildirView.cur = idx
					break
				}
			}
			if found {
				mv, err := g.View(MAILDIR_VIEW)
				if err != nil {
					return err
				}
				err = amua.curMaildirView.Draw(mv)
				if err != nil {
					setStatus(err.Error())
				}
			} else {
				setStatus(amua.searchPattern + " not found")
			}
			return nil
		}
	}
	enterSearch := func(forward bool) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			v.Rewind()
			spbuf, err := ioutil.ReadAll(v)
			if err != nil {
				return err
			}
			prompt := amua.prompt
			amua.searchPattern = strings.TrimSpace(string(spbuf[len(prompt):]))
			switchToMode(amua, g, MaildirMode)
			search(forward)(g, v)
			return nil
		}
	}
	cancelSearch := func(g *gocui.Gui, v *gocui.View) error {
		setStatus("")
		return switchToMode(amua, g, amua.prevMode)
	}
	setFlag := func(flag MessageFlags) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			m := amua.curMessage()
			m.Flags |= flag
			amua.curMaildirView.Draw(v)
			return nil
		}
	}
	unsetFlag := func(flag MessageFlags) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			m := amua.curMessage()
			m.Flags &= ^flag
			amua.curMaildirView.Draw(v)
			return nil
		}
	}
	toggleFlag := func(flag MessageFlags) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			m := amua.curMessage()
			if (m.Flags & flag) != 0 {
				m.Flags &= ^flag
			} else {
				m.Flags |= flag
			}
			amua.curMaildirView.Draw(v)
			return nil
		}
	}
	quit := func(g *gocui.Gui, v *gocui.View) error {
		amua.applyCurMaildirChanges()
		return gocui.ErrQuit
	}

	deleteMessage := setFlag(Trashed)
	undeleteMessage := unsetFlag(Trashed)
	unreadMessage := unsetFlag(Seen)
	readMessage := setFlag(Seen)
	toggleFlagged := toggleFlag(Flagged)

	syncMaildir := func(g *gocui.Gui, v *gocui.View) error {
		amua.applyCurMaildirChanges()
		amua.RefreshMaildir(g, v)
		v, _ = g.View(SIDE_VIEW)
		drawKnownMaildirs(amua, g, v)
		return nil
	}
	commandEnter := func(g *gocui.Gui, v *gocui.View) error {
		switch amua.mode {
		case CommandSearchMode:
			return enterSearch(true)(g, v)
		case CommandMailModeTo:
			var err error
			amua.newMail.to, err = mail.ParseAddressList(getPromptInput())
			if err != nil {
				displayError(err.Error())
				return nil
			}
			setStatus("")
			switchToMode(amua, g, SendMailMode)
		case CommandMailModeCc:
			var err error
			amua.newMail.cc, err = mail.ParseAddressList(getPromptInput())
			if err != nil {
				//flash error
				return nil
			}
			setStatus("")
			switchToMode(amua, g, SendMailMode)
		case CommandMailModeBcc:
			var err error
			amua.newMail.bcc, err = mail.ParseAddressList(getPromptInput())
			if err != nil {
				//flash error
				return nil
			}
			setStatus("")
			switchToMode(amua, g, SendMailMode)
		case CommandNewMailMode:
			if len(amua.newMail.to) == 0 {
				var err error
				amua.newMail.to, err = mail.ParseAddressList(getPromptInput())
				if err != nil {
					displayError(err.Error())
					return nil
				}
				displayPromptWithPrefill(SUBJECT_PROMPT, amua.newMail.subject)
				amua.newMail.subject = ""
			} else if amua.newMail.subject == "" {
				amua.newMail.subject = getPromptInput()
				/* Exec $EDITOR */
				tf, err := ioutil.TempFile("", "amuamail")
				if err != nil {
					log.Fatal(err)
				}
				defer os.Remove(tf.Name())
				tf.Close()
				err = ioutil.WriteFile(tf.Name(), amua.newMail.body, 0600)
				if err != nil {
					log.Fatal(err)
				}

				cmd := exec.Command(amua.ExtEditor(), tf.Name())
				cmd.Stdin = os.Stdin
				cmd.Stdout = os.Stdout
				if err := cmd.Run(); err != nil {
					log.Fatal(err)
				}
				amua.newMail.body, err = ioutil.ReadFile(tf.Name())
				if err != nil {
					log.Fatal(err.Error())
				}
				setStatus("")
				switchToMode(amua, g, SendMailMode)
				err = g.Sync()
				if err != nil {
					log.Fatal(err)
				}
			}
		}
		return nil
	}
	sendMail := func(g *gocui.Gui, v *gocui.View) error {
		err := send(&amua.newMail, cfg)
		if err != nil {
			setStatus(err.Error())
			return nil
		}
		setStatus("Sent to " + cfg.SMTPConfig.Host)
		switchToMode(amua, g, MaildirMode)
		amua.newMail = NewMail{}
		return nil
	}
	reply := func(group bool) func(g *gocui.Gui, v *gocui.View) error {
		return func(g *gocui.Gui, v *gocui.View) error {
			m := amua.curMessage()
			amua.newMail.to = buildTo(m)
			if group {
				amua.newMail.cc = buildCCs(m)
			}
			amua.newMail.subject = "Re: " + m.Subject
			buf, err := ioutil.ReadAll((*MessageAsText)(m))
			if err != nil {
				return err
			}
			buf = bytes.Replace(buf, []byte("\n"), []byte("\n> "), -1)
			replyHeader := fmt.Sprintf("On %s, %s wrote:\n> ", m.Date.Format("Mon Jan 2 15:04:05 -0700 MST 2006"), m.From)
			amua.newMail.body = append([]byte(replyHeader), buf...)
			switchToMode(amua, g, CommandNewMailMode)
			return nil
		}
	}
	replyMessage := reply(false)
	groupReplyMessage := reply(true)
	pipeMessage := func(g *gocui.Gui, v *gocui.View) error {
		m := amua.curMessage()
		cmd := exec.Command(amua.ExtEditor(), m.path)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		if err := cmd.Run(); err != nil {
			log.Fatal(err)
		}
		setStatus("")
		switchToMode(amua, g, MaildirMode)
		err := g.Sync()
		if err != nil {
			log.Fatal(err)
		}
		/* exec a command, pipe the message there */
		return nil
	}
	type keybinding struct {
		key interface{}
		fn  gocui.KeybindingHandler
		mod bool
	}
	bindings := map[string][]keybinding{
		MAILDIR_VIEW: {
			{gocui.KeyEnter, switchToModeInt(MessageMode), false},
			{'c', switchToModeInt(KnownMaildirsMode), false},
			{'v', switchToModeInt(MessageMimeMode), false},
			{'q', quit, false},
			{'d', deleteMessage, false},
			{'u', undeleteMessage, false},
			{'G', maildirAllDown(), false},
			{'k', maildirMove(-1), false},
			{gocui.KeyArrowUp, maildirMove(-1), false},
			{'j', maildirMove(1), false},
			{'n', search(true), false},
			{'N', search(false), false},
			{'$', syncMaildir, false},
			{'F', toggleFlagged, false},
			{gocui.KeyCtrlR, readMessage, false},
			{gocui.KeyCtrlN, unreadMessage, false},
			{gocui.KeyArrowDown, maildirMove(1), false},
			{gocui.KeyCtrlF, maildirMove(10), false},
			{gocui.KeyPgdn, maildirMove(10), false},
			{gocui.KeyCtrlB, maildirMove(-10), false},
			{gocui.KeyPgup, maildirMove(-10), false},
			{'/', switchToModeInt(CommandSearchMode), false},
			{'m', switchToModeInt(CommandNewMailMode), false},
			{'r', replyMessage, false},
			{'g', groupReplyMessage, false},
			{'|', pipeMessage, false},
		},
		MESSAGE_VIEW: {
			{'q', switchToModeInt(MaildirMode), false},
			{'v', messageModeToggle, false},
			{gocui.KeyPgup, scrollMessageView(-10), false},
			{gocui.KeyPgdn, scrollMessageView(10), false},
			{gocui.KeySpace, scrollMessageView(10), false},
			{'j', scrollMessageView(1), false},
			{'k', scrollMessageView(-1), false},
			{'r', replyMessage, false},
			{'g', groupReplyMessage, false},
			{'|', pipeMessage, false},
		},
		SEND_MAIL_VIEW: {
			{'q', switchToModeInt(MaildirMode), false},
			{'t', switchToModeInt(CommandMailModeTo), false},
			{'c', switchToModeInt(CommandMailModeCc), false},
			{'b', switchToModeInt(CommandMailModeBcc), false},
			{'y', sendMail, false},
			{gocui.KeyCtrlG, switchToModeInt(MaildirMode), false},
		},
		STATUS_VIEW: {
			{gocui.KeyEnter, commandEnter, false},
			{gocui.KeyCtrlG, cancelSearch, false},
		},
		SIDE_VIEW: {
			{'j', scrollSideView(amua, 1), false},
			{gocui.KeyArrowDown, scrollSideView(amua, 1), false},
			{'k', scrollSideView(amua, -1), false},
			{gocui.KeyArrowUp, scrollSideView(amua, 1), false},
			{gocui.KeyEnter, selectNewMaildir(amua), false},
		},
		"": {
			{gocui.KeyCtrlC, quit, false},
		},
	}

	for vn, binds := range bindings {
		for _, b := range binds {
			err := g.SetKeybinding(vn, b.key, gocui.ModNone, b.fn)
			if err != nil {
				return err
			}
		}
	}
	return nil
}
Пример #6
0
func modeToView(g *gocui.Gui, mode Mode) *gocui.View {
	v, _ := g.View(modeToViewStr(mode))
	return v
}