Ver a proveniência

plugins/base: save message as draft

master
Simon Ser há 4 anos
ascendente
cometimento
bfc617b702
Não foi encontrada uma chave conhecida para esta assinatura, na base de dados ID da chave GPG: FDE7BE0E88F5E48
4 ficheiros alterados com 98 adições e 45 eliminações
  1. +45
    -0
      plugins/base/imap.go
  2. +1
    -0
      plugins/base/public/compose.html
  3. +51
    -44
      plugins/base/routes.go
  4. +1
    -1
      plugins/lua/lua.go

+ 45
- 0
plugins/base/imap.go Ver ficheiro

@@ -2,12 +2,15 @@ package koushinbase


import ( import (
"bufio" "bufio"
"bytes"
"fmt" "fmt"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time"


"github.com/emersion/go-imap" "github.com/emersion/go-imap"
imapspecialuse "github.com/emersion/go-imap-specialuse"
imapclient "github.com/emersion/go-imap/client" imapclient "github.com/emersion/go-imap/client"
"github.com/emersion/go-message" "github.com/emersion/go-message"
"github.com/emersion/go-message/textproto" "github.com/emersion/go-message/textproto"
@@ -375,3 +378,45 @@ func markMessageAnswered(conn *imapclient.Client, mboxName string, uid uint32) e
flags := []interface{}{imap.AnsweredFlag} flags := []interface{}{imap.AnsweredFlag}
return conn.UidStore(seqSet, item, flags, nil) return conn.UidStore(seqSet, item, flags, nil)
} }

type mailboxType int

const (
mailboxSent mailboxType = iota
mailboxDrafts
)

func appendMessage(c *imapclient.Client, msg *OutgoingMessage, mboxType mailboxType) (saved bool, err error) {
var mboxAttr string
switch mboxType {
case mailboxSent:
mboxAttr = imapspecialuse.Sent
case mailboxDrafts:
mboxAttr = imapspecialuse.Drafts
}

mbox, err := getMailboxByAttribute(c, mboxAttr)
if err != nil {
return false, err
}
if mbox == nil {
return false, nil
}

// IMAP needs to know in advance the final size of the message, so
// there's no way around storing it in a buffer here.
var buf bytes.Buffer
if err := msg.WriteTo(&buf); err != nil {
return false, err
}

flags := []string{imap.SeenFlag}
if mboxType == mailboxDrafts {
flags = append(flags, imap.DraftFlag)
}
if err := c.Append(mbox.Name, flags, time.Now(), &buf); err != nil {
return false, err
}

return true, nil
}

+ 1
- 0
plugins/base/public/compose.html Ver ficheiro

@@ -26,6 +26,7 @@
<label for="attachments">Attachments:</label> <label for="attachments">Attachments:</label>
<input type="file" name="attachments" id="attachments" multiple> <input type="file" name="attachments" id="attachments" multiple>
<br><br> <br><br>
<input type="submit" name="save_as_draft" value="Save as draft">
<input type="submit" value="Send"> <input type="submit" value="Send">
</form> </form>




+ 51
- 44
plugins/base/routes.go Ver ficheiro

@@ -1,7 +1,6 @@
package koushinbase package koushinbase


import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"mime" "mime"
@@ -9,12 +8,10 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"strings" "strings"
"time"


"git.sr.ht/~emersion/koushin" "git.sr.ht/~emersion/koushin"
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
imapmove "github.com/emersion/go-imap-move" imapmove "github.com/emersion/go-imap-move"
imapspecialuse "github.com/emersion/go-imap-specialuse"
imapclient "github.com/emersion/go-imap/client" imapclient "github.com/emersion/go-imap/client"
"github.com/emersion/go-message" "github.com/emersion/go-message"
"github.com/emersion/go-smtp" "github.com/emersion/go-smtp"
@@ -281,6 +278,39 @@ type ComposeRenderData struct {
Message *OutgoingMessage Message *OutgoingMessage
} }


// Send message, append it to the Sent mailbox, mark the original message as
// answered
func submitCompose(ctx *koushin.Context, msg *OutgoingMessage, inReplyToMboxName string, inReplyToUid uint32) error {
err := ctx.Session.DoSMTP(func(c *smtp.Client) error {
return sendMessage(c, msg)
})
if err != nil {
if _, ok := err.(koushin.AuthError); ok {
return echo.NewHTTPError(http.StatusForbidden, err)
}
return fmt.Errorf("failed to send message: %v", err)
}

if inReplyToUid != 0 {
err = ctx.Session.DoIMAP(func(c *imapclient.Client) error {
return markMessageAnswered(c, inReplyToMboxName, inReplyToUid)
})
if err != nil {
return fmt.Errorf("failed to mark original message as answered: %v", err)
}
}

err = ctx.Session.DoIMAP(func(c *imapclient.Client) error {
_, err := appendMessage(c, msg, mailboxSent)
return err
})
if err != nil {
return fmt.Errorf("failed to save message to Sent mailbox: %v", err)
}

return ctx.Redirect(http.StatusFound, "/mailbox/INBOX")
}

func handleCompose(ctx *koushin.Context) error { func handleCompose(ctx *koushin.Context) error {
var msg OutgoingMessage var msg OutgoingMessage
if strings.ContainsRune(ctx.Session.Username(), '@') { if strings.ContainsRune(ctx.Session.Username(), '@') {
@@ -355,6 +385,12 @@ func handleCompose(ctx *koushin.Context) error {
} }


if ctx.Request().Method == http.MethodPost { if ctx.Request().Method == http.MethodPost {
formParams, err := ctx.FormParams()
if err != nil {
return fmt.Errorf("failed to parse form: %v", err)
}
_, saveAsDraft := formParams["save_as_draft"]

msg.From = ctx.FormValue("from") msg.From = ctx.FormValue("from")
msg.To = parseAddressList(ctx.FormValue("to")) msg.To = parseAddressList(ctx.FormValue("to"))
msg.Subject = ctx.FormValue("subject") msg.Subject = ctx.FormValue("subject")
@@ -367,52 +403,23 @@ func handleCompose(ctx *koushin.Context) error {
} }
msg.Attachments = form.File["attachments"] msg.Attachments = form.File["attachments"]


err = ctx.Session.DoSMTP(func(c *smtp.Client) error {
return sendMessage(c, &msg)
})
if err != nil {
if _, ok := err.(koushin.AuthError); ok {
return echo.NewHTTPError(http.StatusForbidden, err)
}
return fmt.Errorf("failed to send message: %v", err)
}

if inReplyToUid != 0 {
if saveAsDraft {
err = ctx.Session.DoIMAP(func(c *imapclient.Client) error { err = ctx.Session.DoIMAP(func(c *imapclient.Client) error {
return markMessageAnswered(c, inReplyToMboxName, inReplyToUid)
copied, err := appendMessage(c, &msg, mailboxDrafts)
if err != nil {
return err
}
if !copied {
return fmt.Errorf("no Draft mailbox found")
}
return nil
}) })
if err != nil { if err != nil {
return fmt.Errorf("failed to mark original message as answered: %v", err)
}
}

err = ctx.Session.DoIMAP(func(c *imapclient.Client) error {
mbox, err := getMailboxByAttribute(c, imapspecialuse.Sent)
if err != nil {
return err
return fmt.Errorf("failed to save message to Draft mailbox: %v", err)
} }
if mbox == nil {
return nil
}

// IMAP needs to know in advance the final size of the message, so
// there's no way around storing it in a buffer here.
var buf bytes.Buffer
if err := msg.WriteTo(&buf); err != nil {
return err
}

flags := []string{imap.SeenFlag}
return c.Append(mbox.Name, flags, time.Now(), &buf)
})
if err != nil {
return fmt.Errorf("failed to save message to Sent mailbox: %v", err)
} else {
return submitCompose(ctx, &msg, inReplyToMboxName, inReplyToUid)
} }

// TODO: append to IMAP Sent mailbox
// TODO: add \Answered flag to original IMAP message

return ctx.Redirect(http.StatusFound, "/mailbox/INBOX")
} }


return ctx.Render(http.StatusOK, "compose.html", &ComposeRenderData{ return ctx.Render(http.StatusOK, "compose.html", &ComposeRenderData{


+ 1
- 1
plugins/lua/lua.go Ver ficheiro

@@ -5,10 +5,10 @@ import (
"html/template" "html/template"
"path/filepath" "path/filepath"


"git.sr.ht/~emersion/koushin"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/yuin/gopher-lua" "github.com/yuin/gopher-lua"
"layeh.com/gopher-luar" "layeh.com/gopher-luar"
"git.sr.ht/~emersion/koushin"
) )


type luaRoute struct { type luaRoute struct {


Carregando…
Cancelar
Guardar