Files
archivmail/cmd/archivmail-export/main.go
T
sysops 2bab61209c chore: Modulname github.com/archivmail → archivmail
Go-Modul in go.mod und allen 45 Go-Dateien umbenannt.
2026-04-05 20:37:35 +02:00

118 lines
2.4 KiB
Go

package main
import (
"flag"
"fmt"
"log/slog"
"os"
"path/filepath"
"archivmail/config"
"archivmail/internal/index"
"archivmail/internal/storage"
)
func main() {
configPath := flag.String("config", "/etc/archivmail/config.yml", "path to config file")
format := flag.String("format", "eml", "export format: eml or pdf")
outDir := flag.String("out", "./export", "output directory")
flag.Parse()
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
if *format == "pdf" {
fmt.Fprintln(os.Stdout, "PDF export not yet implemented")
os.Exit(0)
}
if *format != "eml" {
fmt.Fprintf(os.Stderr, "unknown format: %s (supported: eml, pdf)\n", *format)
os.Exit(1)
}
cfg, err := config.Load(*configPath)
if err != nil {
logger.Error("failed to load config", "err", err)
os.Exit(1)
}
mailStore, err := storage.New(cfg.Storage.StorePath)
if err != nil {
logger.Error("storage init failed", "err", err)
os.Exit(1)
}
indexBackend := cfg.Index.Backend
if indexBackend == "" {
indexBackend = "xapian"
}
batchSize := cfg.Index.BatchSize
if batchSize <= 0 {
batchSize = 100
}
idx, err := index.New(cfg.Index.Path, batchSize, indexBackend)
if err != nil {
logger.Error("index init failed", "err", err)
os.Exit(1)
}
defer idx.Close()
if err := os.MkdirAll(*outDir, 0o755); err != nil {
logger.Error("cannot create output directory", "dir", *outDir, "err", err)
os.Exit(1)
}
// Fetch all indexed mails using pagination
page := 0
pageSize := 500
exported := 0
errors := 0
for {
result, err := idx.Search(index.SearchRequest{
PageSize: pageSize,
Page: page,
})
if err != nil {
logger.Error("search failed", "err", err)
os.Exit(1)
}
if len(result.Hits) == 0 {
break
}
for _, hit := range result.Hits {
raw, err := mailStore.Load(hit.ID)
if err != nil {
logger.Error("load failed", "id", hit.ID, "err", err)
errors++
continue
}
outPath := filepath.Join(*outDir, hit.ID+".eml")
if err := os.WriteFile(outPath, raw, 0o644); err != nil {
logger.Error("write failed", "path", outPath, "err", err)
errors++
continue
}
exported++
}
logger.Info("export progress", "page", page, "exported", exported, "errors", errors)
if exported+errors >= result.Total {
break
}
page++
}
logger.Info("export complete",
"format", *format,
"out", *outDir,
"exported", exported,
"errors", errors,
)
}