mirror of
https://github.com/mjl-/mox.git
synced 2025-07-12 17:04:39 +03:00
implement exporting of all mailboxes/messages as zip/tgz of mbox/maildir
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@ -109,7 +112,12 @@ func accountHandle(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method == "GET" && r.URL.Path == "/" {
|
||||
switch r.URL.Path {
|
||||
case "/":
|
||||
if r.Method != "GET" {
|
||||
http.Error(w, "405 - method not allowed - post required", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.Header().Set("Cache-Control", "no-cache; max-age=0")
|
||||
// We typically return the embedded admin.html, but during development it's handy
|
||||
@ -121,9 +129,49 @@ func accountHandle(w http.ResponseWriter, r *http.Request) {
|
||||
} else {
|
||||
w.Write(accountHTML)
|
||||
}
|
||||
return
|
||||
|
||||
case "/mail-export-maildir.tgz", "/mail-export-maildir.zip", "/mail-export-mbox.tgz", "/mail-export-mbox.zip":
|
||||
maildir := strings.Contains(r.URL.Path, "maildir")
|
||||
tgz := strings.Contains(r.URL.Path, ".tgz")
|
||||
|
||||
acc, err := store.OpenAccount(accName)
|
||||
if err != nil {
|
||||
log.Errorx("open account for export", err)
|
||||
http.Error(w, "500 - internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer acc.Close()
|
||||
|
||||
var archiver store.Archiver
|
||||
if tgz {
|
||||
// Don't tempt browsers to "helpfully" decompress.
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
|
||||
gzw := gzip.NewWriter(w)
|
||||
defer func() {
|
||||
gzw.Close()
|
||||
}()
|
||||
archiver = store.TarArchiver{Writer: tar.NewWriter(gzw)}
|
||||
} else {
|
||||
w.Header().Set("Content-Type", "application/zip")
|
||||
archiver = store.ZipArchiver{Writer: zip.NewWriter(w)}
|
||||
}
|
||||
defer func() {
|
||||
if err := archiver.Close(); err != nil {
|
||||
log.Errorx("exporting mail close", err)
|
||||
}
|
||||
}()
|
||||
if err := acc.ExportMessages(log, archiver, maildir, ""); err != nil {
|
||||
log.Errorx("exporting mail", err)
|
||||
}
|
||||
|
||||
default:
|
||||
if strings.HasPrefix(r.URL.Path, "/api/") {
|
||||
accountSherpaHandler.ServeHTTP(w, r.WithContext(context.WithValue(ctx, authCtxKey, accName)))
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
accountSherpaHandler.ServeHTTP(w, r.WithContext(context.WithValue(ctx, authCtxKey, accName)))
|
||||
}
|
||||
|
||||
type ctxKey string
|
||||
|
@ -195,6 +195,15 @@ const index = async () => {
|
||||
}
|
||||
},
|
||||
),
|
||||
dom.br(),
|
||||
dom.h2('Export'),
|
||||
dom.p('Export all messages in all mailboxes. Either in maildir format (with flags like Replied, Forwarded, Junk, etc) or in mbox format (without flags). And either as .zip file or .tgz file.'),
|
||||
dom.ul(
|
||||
dom.li(dom.a('mail-export-maildir.tgz', attr({href: 'mail-export-maildir.tgz'}))),
|
||||
dom.li(dom.a('mail-export-maildir.zip', attr({href: 'mail-export-maildir.zip'}))),
|
||||
dom.li(dom.a('mail-export-mbox.tgz', attr({href: 'mail-export-mbox.tgz'}))),
|
||||
dom.li(dom.a('mail-export-mbox.zip', attr({href: 'mail-export-mbox.zip'}))),
|
||||
),
|
||||
footer,
|
||||
)
|
||||
}
|
||||
|
Reference in New Issue
Block a user