Silvan Jegen: 1 Implement reply-all functionality for the alps theme 3 files changed, 80 insertions(+), 49 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~migadu/alps-devel/patches/49177/mbox | git am -3Learn more about email & git
We slightly refactor the code to make it easier to read, while we are at it. This should address https://todo.sr.ht/~migadu/alps/155. --- plugins/base/routes.go | 127 ++++++++++++++++++++++++--------------- themes/alps/compose.html | 1 + themes/alps/message.html | 1 + 3 files changed, 80 insertions(+), 49 deletions(-) diff --git a/plugins/base/routes.go b/plugins/base/routes.go index ba3de30..8aaed73 100644 --- a/plugins/base/routes.go +++ b/plugins/base/routes.go @@ -811,65 +811,94 @@ func handleReply(ctx *alps.Context) error { var msg OutgoingMessage if ctx.Request().Method == http.MethodGet { - // Populate fields from original message - partPath, err := parsePartPath(ctx.QueryParam("part")) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err) - } - - var inReplyTo *IMAPMessage - var part *message.Entity - err = ctx.Session.DoIMAP(func(c *imapclient.Client) error { - var err error - inReplyTo, part, err = getMessagePart(c, inReplyToPath.Mailbox, inReplyToPath.Uid, partPath) - return err - }) + msg, err = populateMessageFromOriginalMessage(ctx, inReplyToPath) if err != nil { return err } + } - mimeType, _, err := part.Header.ContentType() + return handleCompose(ctx, &msg, &composeOptions{InReplyTo: &inReplyToPath}) +} + +func populateMessageFromOriginalMessage(ctx *alps.Context, inReplyToPath messagePath) (OutgoingMessage, error) { + var ret OutgoingMessage + + partPath, err := parsePartPath(ctx.QueryParam("part")) + if err != nil { + return ret, echo.NewHTTPError(http.StatusBadRequest, err) + } + + var inReplyTo *IMAPMessage + var part *message.Entity + err = ctx.Session.DoIMAP(func(c *imapclient.Client) error { + var err error + inReplyTo, part, err = getMessagePart(c, inReplyToPath.Mailbox, + inReplyToPath.Uid, partPath) + return err + }) + if err != nil { + return ret, err + } + + mimeType, _, err := part.Header.ContentType() + if err != nil { + return ret, fmt.Errorf("failed to parse part Content-Type: %v", err) + } + + var text string + switch mimeType { + case "text/plain": + ret.Text, err = quote(part.Body) + case "text/html": + text, err = html2text.FromReader(part.Body, html2text.Options{}) if err != nil { - return fmt.Errorf("failed to parse part Content-Type: %v", err) + return ret, err } - if mimeType == "text/plain" { - msg.Text, err = quote(part.Body) - if err != nil { - return err - } - } else if mimeType == "text/html" { - text, err := html2text.FromReader(part.Body, html2text.Options{}) - if err != nil { - return err - } - msg.Text, err = quote(strings.NewReader(text)) - if err != nil { - return nil - } - } else { - err := fmt.Errorf("cannot forward %q part", mimeType) - return echo.NewHTTPError(http.StatusBadRequest, err) - } + ret.Text, err = quote(strings.NewReader(text)) - var hdr mail.Header - hdr.GenerateMessageID() - mid, _ := hdr.MessageID() - msg.MessageID = "<" + mid + ">" - msg.InReplyTo = inReplyTo.Envelope.MessageID - // TODO: populate From from known user addresses and inReplyTo.Envelope.To - replyTo := inReplyTo.Envelope.ReplyTo - if len(replyTo) == 0 { - replyTo = inReplyTo.Envelope.From - } - msg.To = unwrapIMAPAddressList(replyTo) - msg.Subject = inReplyTo.Envelope.Subject - if !strings.HasPrefix(strings.ToLower(msg.Subject), "re:") { - msg.Subject = "Re: " + msg.Subject - } + default: + err := fmt.Errorf("cannot forward %q part", mimeType) + err = echo.NewHTTPError(http.StatusBadRequest, err) + } + if err != nil { + return ret, err } - return handleCompose(ctx, &msg, &composeOptions{InReplyTo: &inReplyToPath}) + var hdr mail.Header + hdr.GenerateMessageID() + mid, _ := hdr.MessageID() + ret.MessageID = "<" + mid + ">" + ret.InReplyTo = inReplyTo.Envelope.MessageID + // TODO: populate From from known user addresses and inReplyTo.Envelope.To + replyTo := inReplyTo.Envelope.ReplyTo + if len(replyTo) == 0 { + replyTo = inReplyTo.Envelope.From + } + ret.To = unwrapIMAPAddressList(replyTo) + + if ctx.QueryParam("all") != "" { + filtered := filterOutUsername(ctx.Session.Username(), + inReplyTo.Envelope.To) + ret.To = unwrapIMAPAddressList(append(replyTo, filtered...)) + ret.Cc = unwrapIMAPAddressList(inReplyTo.Envelope.Cc) + } + + ret.Subject = inReplyTo.Envelope.Subject + if !strings.HasPrefix(strings.ToLower(ret.Subject), "re:") { + ret.Subject = "Re: " + ret.Subject + } + + return ret, nil +} + +func filterOutUsername(username string, addresses []imap.Address) []imap.Address { + for i, addr := range addresses { + if addr.Addr() == username { + return append(addresses[:i], addresses[i+1:]...) + } + } + return addresses } func handleForward(ctx *alps.Context) error { diff --git a/themes/alps/compose.html b/themes/alps/compose.html index 7d7c822..e424960 100644 --- a/themes/alps/compose.html +++ b/themes/alps/compose.html @@ -34,6 +34,7 @@ type="text" name="cc" id="cc" + value="{{ join .Message.Cc ", " }}" /> <label>Bcc</label> diff --git a/themes/alps/message.html b/themes/alps/message.html index 8f67e8d..daa69ef 100644 --- a/themes/alps/message.html +++ b/themes/alps/message.html @@ -83,6 +83,7 @@ <a class="action-group button-link" href="{{.Message.URL}}/edit{{if .Message.TextPart}}?part={{.Message.TextPart.PathString}}{{end}}">Edit draft</a> {{else}} <a class="action-group button-link" href="{{.Message.URL}}/reply{{if .Message.TextPart}}?part={{.Message.TextPart.PathString}}{{end}}">Reply</a> + <a class="action-group button-link" href="{{.Message.URL}}/reply{{if .Message.TextPart}}?part={{.Message.TextPart.PathString}}&all=true{{end}}">Reply all</a> <a class="action-group button-link" href="{{.Message.URL}}/forward{{if .Message.TextPart}}?part={{.Message.TextPart.PathString}}{{end}}">Forward</a> {{end}} </span> -- 2.43.0
LGTM and pushed, thanks! (Please feel free to ping me if I forget about a patch!)