Add export-messages command
Right now only supports exporting conversations, and doesn't support attachments.
This commit is contained in:
parent
ea188ff133
commit
bd861cdb00
|
@ -12,6 +12,7 @@ import (
|
||||||
imapmove "github.com/emersion/go-imap-move"
|
imapmove "github.com/emersion/go-imap-move"
|
||||||
imapspacialuse "github.com/emersion/go-imap-specialuse"
|
imapspacialuse "github.com/emersion/go-imap-specialuse"
|
||||||
imapserver "github.com/emersion/go-imap/server"
|
imapserver "github.com/emersion/go-imap/server"
|
||||||
|
"github.com/emersion/go-mbox"
|
||||||
"github.com/emersion/go-smtp"
|
"github.com/emersion/go-smtp"
|
||||||
"github.com/howeyc/gopass"
|
"github.com/howeyc/gopass"
|
||||||
"golang.org/x/crypto/openpgp"
|
"golang.org/x/crypto/openpgp"
|
||||||
|
@ -20,6 +21,7 @@ import (
|
||||||
"github.com/emersion/hydroxide/auth"
|
"github.com/emersion/hydroxide/auth"
|
||||||
"github.com/emersion/hydroxide/carddav"
|
"github.com/emersion/hydroxide/carddav"
|
||||||
"github.com/emersion/hydroxide/events"
|
"github.com/emersion/hydroxide/events"
|
||||||
|
"github.com/emersion/hydroxide/exports"
|
||||||
imapbackend "github.com/emersion/hydroxide/imap"
|
imapbackend "github.com/emersion/hydroxide/imap"
|
||||||
"github.com/emersion/hydroxide/imports"
|
"github.com/emersion/hydroxide/imports"
|
||||||
"github.com/emersion/hydroxide/protonmail"
|
"github.com/emersion/hydroxide/protonmail"
|
||||||
|
@ -116,6 +118,7 @@ Commands:
|
||||||
export-secret-keys <username> Export secret keys
|
export-secret-keys <username> Export secret keys
|
||||||
imap Run hydroxide as an IMAP server
|
imap Run hydroxide as an IMAP server
|
||||||
import-messages <username> <file> Import messages
|
import-messages <username> <file> Import messages
|
||||||
|
export-messages [options...] <username> Export messages
|
||||||
serve Run all servers
|
serve Run all servers
|
||||||
smtp Run hydroxide as an SMTP server
|
smtp Run hydroxide as an SMTP server
|
||||||
status View hydroxide status
|
status View hydroxide status
|
||||||
|
@ -151,6 +154,7 @@ func main() {
|
||||||
authCmd := flag.NewFlagSet("auth", flag.ExitOnError)
|
authCmd := flag.NewFlagSet("auth", flag.ExitOnError)
|
||||||
exportSecretKeysCmd := flag.NewFlagSet("export-secret-keys", flag.ExitOnError)
|
exportSecretKeysCmd := flag.NewFlagSet("export-secret-keys", flag.ExitOnError)
|
||||||
importMessagesCmd := flag.NewFlagSet("import-messages", flag.ExitOnError)
|
importMessagesCmd := flag.NewFlagSet("import-messages", flag.ExitOnError)
|
||||||
|
exportMessagesCmd := flag.NewFlagSet("export-messages", flag.ExitOnError)
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -335,6 +339,38 @@ func main() {
|
||||||
if err := imports.ImportMessage(c, f); err != nil {
|
if err := imports.ImportMessage(c, f); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
case "export-messages":
|
||||||
|
var convID string
|
||||||
|
exportMessagesCmd.StringVar(&convID, "conversation-id", "", "conversation ID")
|
||||||
|
exportMessagesCmd.Parse(flag.Args()[1:])
|
||||||
|
username := exportMessagesCmd.Arg(0)
|
||||||
|
log.Println(convID, username)
|
||||||
|
if convID == "" || username == "" {
|
||||||
|
log.Fatal("usage: hydroxide export-messages -conversation-id <id> <username>")
|
||||||
|
}
|
||||||
|
|
||||||
|
var bridgePassword string
|
||||||
|
fmt.Fprintf(os.Stderr, "Bridge password: ")
|
||||||
|
if pass, err := gopass.GetPasswd(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
bridgePassword = string(pass)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, privateKeys, err := auth.NewManager(newClient).Auth(username, bridgePassword)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mboxWriter := mbox.NewWriter(os.Stdout)
|
||||||
|
|
||||||
|
if err := exports.ExportConversation(c, privateKeys, mboxWriter, convID); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mboxWriter.Close(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
case "smtp":
|
case "smtp":
|
||||||
addr := *smtpHost + ":" + *smtpPort
|
addr := *smtpHost + ":" + *smtpPort
|
||||||
authManager := auth.NewManager(newClient)
|
authManager := auth.NewManager(newClient)
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package exports
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"bufio"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/emersion/go-mbox"
|
||||||
|
"github.com/emersion/go-message"
|
||||||
|
"github.com/emersion/go-message/mail"
|
||||||
|
"github.com/emersion/go-message/textproto"
|
||||||
|
"golang.org/x/crypto/openpgp"
|
||||||
|
|
||||||
|
"github.com/emersion/hydroxide/protonmail"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExportMessage(c *protonmail.Client, privateKeys openpgp.KeyRing, w io.Writer, id string) error {
|
||||||
|
msg, err := c.GetMessage(id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch message: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mimeType := msg.MIMEType
|
||||||
|
if mimeType == "" {
|
||||||
|
mimeType = "text/html"
|
||||||
|
}
|
||||||
|
|
||||||
|
br := bufio.NewReader(strings.NewReader(msg.Header))
|
||||||
|
th, err := textproto.ReadHeader(br)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read message header: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mh := mail.Header{message.Header{th}}
|
||||||
|
mh.SetContentType(mimeType, nil)
|
||||||
|
mh.Set("Content-Transfer-Encoding", "quoted-printable")
|
||||||
|
|
||||||
|
// TODO: add support for attachments
|
||||||
|
mw, err := mail.CreateSingleInlineWriter(w, mh)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create message writer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
md, err := msg.Read(privateKeys, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check signature
|
||||||
|
if _, err := io.Copy(mw, md.UnverifiedBody); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mw.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExportConversation(c *protonmail.Client, privateKeys openpgp.KeyRing, mbox *mbox.Writer, id string) error {
|
||||||
|
_, msgs, err := c.GetConversation(id, "")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch conversation: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, msg := range msgs {
|
||||||
|
w, err := mbox.CreateMessage(msg.Sender.Address, msg.Time.Time())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create mbox message: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ExportMessage(c, privateKeys, w, msg.ID); err != nil {
|
||||||
|
return fmt.Errorf("failed to export conversation message: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/emersion/go-imap v1.0.4
|
github.com/emersion/go-imap v1.0.4
|
||||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342
|
||||||
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62
|
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62
|
||||||
|
github.com/emersion/go-mbox v1.0.0
|
||||||
github.com/emersion/go-message v0.11.1
|
github.com/emersion/go-message v0.11.1
|
||||||
github.com/emersion/go-smtp v0.12.1
|
github.com/emersion/go-smtp v0.12.1
|
||||||
github.com/emersion/go-vcard v0.0.0-20191221110513-5f81fa0d3cc7
|
github.com/emersion/go-vcard v0.0.0-20191221110513-5f81fa0d3cc7
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -16,6 +16,8 @@ github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342 h1:5p1t3e1Po
|
||||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342/go.mod h1:QuMaZcKFDVI0yCrnAbPLfbwllz1wtOrZH8/vZ5yzp4w=
|
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342/go.mod h1:QuMaZcKFDVI0yCrnAbPLfbwllz1wtOrZH8/vZ5yzp4w=
|
||||||
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62 h1:4ZAfwfc8aDlj26kkEap1UDSwwDnJp9Ie8Uj1MSXAkPk=
|
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62 h1:4ZAfwfc8aDlj26kkEap1UDSwwDnJp9Ie8Uj1MSXAkPk=
|
||||||
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62/go.mod h1:/nybxhI8kXom8Tw6BrHMl42usALvka6meORflnnYwe4=
|
github.com/emersion/go-imap-specialuse v0.0.0-20161227184202-ba031ced6a62/go.mod h1:/nybxhI8kXom8Tw6BrHMl42usALvka6meORflnnYwe4=
|
||||||
|
github.com/emersion/go-mbox v1.0.0 h1:HN6aKbyqmgIfK9fS/gen+NRr2wXLSxZXWfdAIAnzQPc=
|
||||||
|
github.com/emersion/go-mbox v1.0.0/go.mod h1:Yp9IVuuOYLEuMv4yjgDHvhb5mHOcYH6x92Oas3QqEZI=
|
||||||
github.com/emersion/go-message v0.11.1 h1:0C/S4JIXDTSfXB1vpqdimAYyK4+79fgEAMQ0dSL+Kac=
|
github.com/emersion/go-message v0.11.1 h1:0C/S4JIXDTSfXB1vpqdimAYyK4+79fgEAMQ0dSL+Kac=
|
||||||
github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
||||||
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e h1:ba7YsgX5OV8FjGi5ZWml8Jng6oBrJAb3ahqWMJ5Ce8Q=
|
github.com/emersion/go-sasl v0.0.0-20190817083125-240c8404624e h1:ba7YsgX5OV8FjGi5ZWml8Jng6oBrJAb3ahqWMJ5Ce8Q=
|
||||||
|
|
Loading…
Reference in New Issue