diff options
-rw-r--r-- | conn_pool.go | 2 | ||||
-rw-r--r-- | imap.go | 20 | ||||
-rw-r--r-- | public/mailbox.html | 15 | ||||
-rw-r--r-- | public/message.html | 8 | ||||
-rw-r--r-- | server.go | 23 | ||||
-rw-r--r-- | smtp.go | 10 | ||||
-rw-r--r-- | strconv.go | 2 |
7 files changed, 60 insertions, 20 deletions
diff --git a/conn_pool.go b/conn_pool.go index 69281af..34c51bb 100644 --- a/conn_pool.go +++ b/conn_pool.go @@ -21,7 +21,7 @@ func generateToken() (string, error) { var ErrSessionExpired = errors.New("session expired") type Session struct { - locker sync.Mutex + locker sync.Mutex imapConn *imapclient.Client username, password string } @@ -206,23 +206,23 @@ func (msg *imapMessage) PartTree() *IMAPPartNode { return imapPartTree(msg.BodyStructure, nil) } -func listMessages(conn *imapclient.Client, mboxName string) ([]imapMessage, error) { +func listMessages(conn *imapclient.Client, mboxName string, page int) ([]imapMessage, error) { if err := ensureMailboxSelected(conn, mboxName); err != nil { return nil, err } - n := uint32(50) - mbox := conn.Mailbox() - from := uint32(1) - to := mbox.Messages - if mbox.Messages == 0 { + to := int(mbox.Messages) - page*messagesPerPage + from := to - messagesPerPage + if from <= 0 { + from = 1 + } + if to <= 0 { return nil, nil - } else if mbox.Messages > n { - from = mbox.Messages - n } + seqSet := new(imap.SeqSet) - seqSet.AddRange(from, to) + seqSet.AddRange(uint32(from), uint32(to)) fetch := []imap.FetchItem{imap.FetchEnvelope, imap.FetchUid, imap.FetchBodyStructure} @@ -232,7 +232,7 @@ func listMessages(conn *imapclient.Client, mboxName string) ([]imapMessage, erro done <- conn.Fetch(seqSet, fetch, ch) }() - msgs := make([]imapMessage, 0, n) + msgs := make([]imapMessage, 0, to-from) for msg := range ch { msgs = append(msgs, imapMessage{msg}) } diff --git a/public/mailbox.html b/public/mailbox.html index e56efcb..435998c 100644 --- a/public/mailbox.html +++ b/public/mailbox.html @@ -20,10 +20,23 @@ <ul> {{range .Messages}} <li><a href="/message/{{$.Mailbox.Name | pathescape}}/{{.Uid}}?part={{.TextPartName}}"> - {{.Envelope.Subject}} + {{if .Envelope.Subject}} + {{.Envelope.Subject}} + {{else}} + (No subject) + {{end}} </a></li> {{end}} </ul> + + <p> + {{if ge .PrevPage 0}} + <a href="?page={{.PrevPage}}">Prev</a> + {{end}} + {{if ge .NextPage 0}} + <a href="?page={{.NextPage}}">Next</a> + {{end}} + </p> {{else}} <p>Mailbox is empty.</p> {{end}} diff --git a/public/message.html b/public/message.html index 2e1a308..5c18bd0 100644 --- a/public/message.html +++ b/public/message.html @@ -6,7 +6,13 @@ <a href="/mailbox/{{.Mailbox.Name | pathescape}}">Back</a> </p> -<h2>{{.Message.Envelope.Subject}}</h2> +<h2> + {{if .Message.Envelope.Subject}} + {{.Message.Envelope.Subject}} + {{else}} + (No subject) + {{end}} +</h2> {{define "message-part-tree"}} {{/* nested templates can't access the parent's context */}} @@ -6,6 +6,7 @@ import ( "mime" "net/http" "net/url" + "strconv" "strings" "time" @@ -18,6 +19,8 @@ import ( const cookieName = "koushin_session" +const messagesPerPage = 50 + type Server struct { imap struct { host string @@ -366,6 +369,14 @@ func New(imapURL, smtpURL string) *echo.Echo { return echo.NewHTTPError(http.StatusBadRequest, err) } + page := 0 + if pageStr := ctx.QueryParam("page"); pageStr != "" { + var err error + if page, err = strconv.Atoi(pageStr); err != nil || page < 0 { + return echo.NewHTTPError(http.StatusBadRequest, "invalid page index") + } + } + var mailboxes []*imap.MailboxInfo var msgs []imapMessage var mbox *imap.MailboxStatus @@ -374,7 +385,7 @@ func New(imapURL, smtpURL string) *echo.Echo { if mailboxes, err = listMailboxes(c); err != nil { return err } - if msgs, err = listMessages(c, mboxName); err != nil { + if msgs, err = listMessages(c, mboxName, page); err != nil { return err } mbox = c.Mailbox() @@ -384,10 +395,20 @@ func New(imapURL, smtpURL string) *echo.Echo { return err } + prevPage, nextPage := -1, -1 + if page > 0 { + prevPage = page - 1 + } + if (page+1)*messagesPerPage < int(mbox.Messages) { + nextPage = page + 1 + } + return ctx.Render(http.StatusOK, "mailbox.html", map[string]interface{}{ "Mailbox": mbox, "Mailboxes": mailboxes, "Messages": msgs, + "PrevPage": prevPage, + "NextPage": nextPage, }) }) @@ -3,9 +3,9 @@ package koushin import ( "bufio" "fmt" - "time" "io" "strings" + "time" "github.com/emersion/go-message/mail" "github.com/emersion/go-smtp" @@ -50,11 +50,11 @@ func (s *Server) connectSMTP() (*smtp.Client, error) { } type OutgoingMessage struct { - From string - To []string - Subject string + From string + To []string + Subject string InReplyTo string - Text string + Text string } func (msg *OutgoingMessage) ToString() string { @@ -2,9 +2,9 @@ package koushin import ( "fmt" + "net/url" "strconv" "strings" - "net/url" ) func parseUid(s string) (uint32, error) { |