diff options
-rw-r--r-- | go.mod | 14 | ||||
-rw-r--r-- | go.sum | 28 | ||||
-rw-r--r-- | plugins/base/public/message.html | 9 | ||||
-rw-r--r-- | plugins/base/routes.go | 48 | ||||
-rw-r--r-- | plugins/base/strconv.go | 12 | ||||
-rw-r--r-- | themes/sourcehut/message.html | 9 |
6 files changed, 81 insertions, 39 deletions
@@ -5,8 +5,9 @@ go 1.13 require ( github.com/aymerick/douceur v0.2.0 github.com/chris-ramon/douceur v0.2.0 - github.com/emersion/go-ical v0.0.0-20200225182515-5cc64a0054ad // indirect - github.com/emersion/go-imap v1.0.3 + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 // indirect + github.com/emersion/go-imap v1.0.4 github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915 github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62 @@ -17,14 +18,13 @@ require ( github.com/emersion/go-webdav v0.2.1-0.20200227113614-abadf534f49a github.com/google/uuid v1.1.1 github.com/gorilla/css v1.0.0 // indirect - github.com/labstack/echo/v4 v4.1.15-0.20200203180927-504f39abaf32 + github.com/labstack/echo/v4 v4.1.15 github.com/labstack/gommon v0.3.0 - github.com/mattn/go-isatty v0.0.12 // indirect github.com/microcosm-cc/bluemonday v1.0.2 github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 - golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d // indirect - golang.org/x/net v0.0.0-20200225223329-5d076fcf07a8 - golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect + golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 // indirect + golang.org/x/net v0.0.0-20200301022130-244492dfa37a + golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d // indirect layeh.com/gopher-luar v1.0.7 ) @@ -12,10 +12,12 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e h1:YGM1sI7edZOt8KAfX9Miq/X99d2QXdgjkJ7vN4HjxAA= github.com/emersion/go-ical v0.0.0-20200224201310-cd514449c39e/go.mod h1:4xVTBPcT43a1pp3vdaa+FuRdX5XhKCZPpWv7m0z9ByM= -github.com/emersion/go-ical v0.0.0-20200225182515-5cc64a0054ad h1:OKhKFSWeuAbVzgBsas+QCjCFLzi7pRX/FEhDudYHiQw= -github.com/emersion/go-ical v0.0.0-20200225182515-5cc64a0054ad/go.mod h1:4xVTBPcT43a1pp3vdaa+FuRdX5XhKCZPpWv7m0z9ByM= +github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1 h1:v0W797seT60q3pzrphQUKh22Nt8uS7rgZyD6lqYgM0E= +github.com/emersion/go-ical v0.0.0-20200225233454-26ef720b8bf1/go.mod h1:4xVTBPcT43a1pp3vdaa+FuRdX5XhKCZPpWv7m0z9ByM= github.com/emersion/go-imap v1.0.3 h1:5eEee8/DTSIPfliiWqwfvjPGkU8bBtvOy/Wx+eeXzO4= github.com/emersion/go-imap v1.0.3/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= +github.com/emersion/go-imap v1.0.4 h1:uiCAIHM6Z5Jwkma1zdNDWWXxSCqb+/xHBkHflD7XBro= +github.com/emersion/go-imap v1.0.4/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915 h1:8xzODjLqrfAJo+CNhX0Fp47vdVN0ZvmGV3CPt/Ex1nU= github.com/emersion/go-imap-metadata v0.0.0-20200128185110-9d939d2a0915/go.mod h1:6mXMzbK9Ts0mrrBibqy56SqZpuFMry5AedTgu6qY5zM= github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1PomYgLWwEwhwEU5kVBwcyAcVrOpexv8AeZx0= @@ -39,18 +41,17 @@ github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/labstack/echo/v4 v4.1.15-0.20200203180927-504f39abaf32 h1:UiIEDYxPPmjl6mMIY4QPDguD/QAtK+gR4IRMSrjWmeA= -github.com/labstack/echo/v4 v4.1.15-0.20200203180927-504f39abaf32/go.mod h1:mbsytw7LXzfWxMLdvzjjeERCwTL3PI03GIPpUpaMnfQ= +github.com/labstack/echo/v4 v4.1.15 h1:4aE6KfJC+wCnMjODwcpeEGWGsRfszxZMwB3QVTECj2I= +github.com/labstack/echo/v4 v4.1.15/go.mod h1:GWO5IBVzI371K8XJe50CSvHjQCafK6cw8R/moLhEU6o= github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/martinlindhe/base36 v1.0.0 h1:eYsumTah144C0A8P1T/AVSUk5ZoLnhfYFM3OGQxB52A= github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= @@ -72,24 +73,25 @@ github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBU gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 h1:1Coh5BsUBlXoEJmIEaNzVAWrtg9k7/eJzailMQr1grw= gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3/go.mod h1:Gn+LZmCrhPECMD3SOKlE+BOHwhOYD9j7WT9NUtkCrC8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 h1:TjszyFsQsyZNHwdVdZ5m7bjmreu0znc2kRYsEml9/Ww= +golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200225223329-5d076fcf07a8 h1:0hpG1RSqNmKZ60akfzABaMjKAn2762l2+HJyXFT5LMY= -golang.org/x/net v0.0.0-20200225223329-5d076fcf07a8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciMoV+FeI1sRXx/pLDL44= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/plugins/base/public/message.html b/plugins/base/public/message.html index b537ff0..ed2b1a2 100644 --- a/plugins/base/public/message.html +++ b/plugins/base/public/message.html @@ -16,7 +16,8 @@ {{end}} </h2> -<form method="post" action="{{.Message.URL}}/move"> +<form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <label for="move-to">Move to:</label> <select name="to" id="move-to"> {{range .Mailboxes}} @@ -26,12 +27,14 @@ <input type="submit" value="Move"> </form> -<form method="post" action="{{.Message.URL}}/delete"> +<form method="post" action="/message/{{.Mailbox.Name | pathescape}}/delete"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <input type="submit" value="Delete"> </form> {{if .Flags}} - <form method="post" action="{{.Message.URL}}/flag"> + <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/flag"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <p>Flags:</p> {{range $name, $has := .Flags}} {{if ismutableflag $name}} diff --git a/plugins/base/routes.go b/plugins/base/routes.go index 0237634..d2bfe73 100644 --- a/plugins/base/routes.go +++ b/plugins/base/routes.go @@ -53,11 +53,11 @@ func registerRoutes(p *koushin.GoPlugin) { p.GET("/message/:mbox/:uid/edit", handleEdit) p.POST("/message/:mbox/:uid/edit", handleEdit) - p.POST("/message/:mbox/:uid/move", handleMove) + p.POST("/message/:mbox/move", handleMove) - p.POST("/message/:mbox/:uid/delete", handleDelete) + p.POST("/message/:mbox/delete", handleDelete) - p.POST("/message/:mbox/:uid/flag", handleSetFlags) + p.POST("/message/:mbox/flag", handleSetFlags) p.GET("/settings", handleSettings) p.POST("/settings", handleSettings) @@ -654,7 +654,16 @@ func handleEdit(ctx *koushin.Context) error { } func handleMove(ctx *koushin.Context) error { - mboxName, uid, err := parseMboxAndUid(ctx.Param("mbox"), ctx.Param("uid")) + mboxName, err := url.PathUnescape(ctx.Param("mbox")) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + + formParams, err := ctx.FormParams() + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + uids, err := parseUidList(formParams["uids"]) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err) } @@ -669,7 +678,7 @@ func handleMove(ctx *koushin.Context) error { } var seqSet imap.SeqSet - seqSet.AddNum(uid) + seqSet.AddNum(uids...) if err := mc.UidMoveWithFallback(&seqSet, to); err != nil { return fmt.Errorf("failed to move message: %v", err) } @@ -685,7 +694,16 @@ func handleMove(ctx *koushin.Context) error { } func handleDelete(ctx *koushin.Context) error { - mboxName, uid, err := parseMboxAndUid(ctx.Param("mbox"), ctx.Param("uid")) + mboxName, err := url.PathUnescape(ctx.Param("mbox")) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + + formParams, err := ctx.FormParams() + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + uids, err := parseUidList(formParams["uids"]) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err) } @@ -696,7 +714,7 @@ func handleDelete(ctx *koushin.Context) error { } var seqSet imap.SeqSet - seqSet.AddNum(uid) + seqSet.AddNum(uids...) item := imap.FormatFlagsOp(imap.AddFlags, true) flags := []interface{}{imap.DeletedFlag} @@ -724,16 +742,20 @@ func handleDelete(ctx *koushin.Context) error { } func handleSetFlags(ctx *koushin.Context) error { - mboxName, uid, err := parseMboxAndUid(ctx.Param("mbox"), ctx.Param("uid")) + mboxName, err := url.PathUnescape(ctx.Param("mbox")) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err) } - form, err := ctx.FormParams() + formParams, err := ctx.FormParams() + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err) + } + uids, err := parseUidList(formParams["uids"]) if err != nil { return echo.NewHTTPError(http.StatusBadRequest, err) } - flags, ok := form["flags"] + flags, ok := formParams["flags"] if !ok { return echo.NewHTTPError(http.StatusBadRequest, "missing 'flags' form values") } @@ -756,7 +778,7 @@ func handleSetFlags(ctx *koushin.Context) error { } var seqSet imap.SeqSet - seqSet.AddNum(uid) + seqSet.AddNum(uids...) storeItems := make([]interface{}, len(flags)) for i, f := range flags { @@ -774,11 +796,11 @@ func handleSetFlags(ctx *koushin.Context) error { return err } - if op == imap.RemoveFlags && len(flags) == 1 && flags[0] == "\\Seen" { + if len(uids) != 1 || (op == imap.RemoveFlags && len(flags) == 1 && flags[0] == "\\Seen") { // Redirecting to the message view would mark the message as read again return ctx.Redirect(http.StatusFound, fmt.Sprintf("/mailbox/%v", url.PathEscape(mboxName))) } - return ctx.Redirect(http.StatusFound, fmt.Sprintf("/message/%v/%v", url.PathEscape(mboxName), uid)) + return ctx.Redirect(http.StatusFound, fmt.Sprintf("/message/%v/%v", url.PathEscape(mboxName), uids[0])) } const settingsKey = "base.settings" diff --git a/plugins/base/strconv.go b/plugins/base/strconv.go index 1a32e75..9efa4cd 100644 --- a/plugins/base/strconv.go +++ b/plugins/base/strconv.go @@ -27,6 +27,18 @@ func parseMboxAndUid(mboxString, uidString string) (string, uint32, error) { return mboxName, uid, err } +func parseUidList(values []string) ([]uint32, error) { + var uids []uint32 + for _, v := range values { + uid, err := parseUid(v) + if err != nil { + return nil, err + } + uids = append(uids, uid) + } + return uids, nil +} + func parsePartPath(s string) ([]int, error) { if s == "" { return nil, nil diff --git a/themes/sourcehut/message.html b/themes/sourcehut/message.html index af39b15..1e4197f 100644 --- a/themes/sourcehut/message.html +++ b/themes/sourcehut/message.html @@ -124,7 +124,8 @@ <details> <summary>Move to another mailbox</summary> - <form method="post" action="{{.Message.URL}}/move"> + <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/move"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <div class="form-group"> <select class="form-control" name="to" id="move-to"> {{range .Mailboxes}} @@ -140,7 +141,8 @@ <details> <summary>Delete</summary> - <form method="post" action="{{.Message.URL}}/delete"> + <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/delete"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <p>Are you sure?</p> <div class="pull-right"> <button class="btn btn-danger">Delete</button> @@ -151,7 +153,8 @@ {{if .Flags}} <details> <summary>Edit flags</summary> - <form method="post" action="{{.Message.URL}}/flag"> + <form method="post" action="/message/{{.Mailbox.Name | pathescape}}/flag"> + <input type="hidden" name="uids" value="{{.Message.Uid}}"> <div class="form-group"> {{range $name, $has := .Flags}} {{if ismutableflag $name}} |