From 2f337ee2000d8c5be4999719e67f5540d9a73d6f Mon Sep 17 00:00:00 2001 From: DonVoo Date: Mon, 13 Jul 2026 03:06:11 +0200 Subject: [PATCH] Load messages from selected source folder --- backend/00-router.go | 107 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/backend/00-router.go b/backend/00-router.go index d659dea..ec04817 100644 --- a/backend/00-router.go +++ b/backend/00-router.go @@ -1,11 +1,13 @@ package backend import ( + "bytes" "database/sql" "errors" "fmt" "html" "net/http" + "net/mail" "net/url" "os" "path/filepath" @@ -39,6 +41,8 @@ func RegisterRoutes(mux *http.ServeMux) { mux.HandleFunc("/transfer", transferHandler) mux.HandleFunc("/transfer/", transferHandler) mux.HandleFunc("/boxes/source", emailBoxHandler) + mux.HandleFunc("/boxes/source/messages", sourceMailboxMessagesHandler) + mux.HandleFunc("/boxes/source/message", sourceMailboxMessageHandler) mux.HandleFunc("/boxes/target", emailBoxHandler) mux.HandleFunc("/migrate/run", migrateRunHandler) // TODO Codex: RunMigration im Hintergrund mux.HandleFunc("/migrate/status", migrateStatusHandler) // TODO Codex: jobs-Fortschritt (HTMX-Poll) @@ -314,6 +318,63 @@ func emailBoxHandler(w http.ResponseWriter, r *http.Request) { } } +func sourceMailboxMessagesHandler(w http.ResponseWriter, r *http.Request) { + accountName := strings.TrimSpace(r.URL.Query().Get("source")) + folder := strings.TrimSpace(r.URL.Query().Get("folder")) + w.Header().Set("Content-Type", "text/html; charset=utf-8") + if accountName == "" || folder == "" { + fmt.Fprint(w, `
Nachrichten
Quell-Postfach und Ordner waehlen.
`) + return + } + account, err := GetAccount(accountName) + if err != nil { + fmt.Fprintf(w, `
Nachrichten
%s
`, html.EscapeString(err.Error())) + return + } + messages, err := fetchSourceFolderMessages(account, folder) + if err != nil { + fmt.Fprintf(w, `
Nachrichten
%s
`, html.EscapeString(err.Error())) + return + } + renderSourceMailboxMessageList(w, account, folder, messages) +} + +func sourceMailboxMessageHandler(w http.ResponseWriter, r *http.Request) { + accountName := strings.TrimSpace(r.URL.Query().Get("source")) + folder := strings.TrimSpace(r.URL.Query().Get("folder")) + index, err := strconv.Atoi(r.URL.Query().Get("index")) + if err != nil { + http.Error(w, "bad index", http.StatusBadRequest) + return + } + account, err := GetAccount(accountName) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + messages, err := fetchSourceFolderMessages(account, folder) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if index < 0 || index >= len(messages) { + http.Error(w, "message index out of range", http.StatusNotFound) + return + } + raw := messages[index].Body + msg, err := mail.ReadMessage(bytes.NewReader(raw)) + if err != nil { + renderReadPaneWithSource(w, account.Name, folder, "", index, "(unlesbar)", "", "", string(raw)) + return + } + renderReadPaneWithSource(w, account.Name, folder, "", index, + decodeHeader(msg.Header.Get("Subject")), + decodeHeader(msg.Header.Get("From")), + decodeHeader(msg.Header.Get("Date")), + messageBody(raw), + ) +} + func archiveCreateHandler(w http.ResponseWriter, r *http.Request) { if !requireManager(w, r) { return @@ -920,8 +981,50 @@ func renderSourceFolders(b *strings.Builder, account Account) { return } for _, folder := range folders { - fmt.Fprintf(b, `
%s%s
`, - html.EscapeString(folder.Name), html.EscapeString(strings.Join(folder.Attrs, " "))) + fmt.Fprintf(b, `%s%s`, + urlEsc(account.Name), urlEsc(folder.Name), html.EscapeString(folder.Name), html.EscapeString(strings.Join(folder.Attrs, " "))) + } +} + +func fetchSourceFolderMessages(account Account, folder string) ([]RawMessage, error) { + if accountProto(account) == "pop3" { + src, err := OpenPOP3Source(account) + if err != nil { + return nil, err + } + defer src.Close() + return src.Fetch(folder) + } + src, err := OpenIMAPSource(account) + if err != nil { + return nil, err + } + defer src.Close() + return src.Fetch(folder) +} + +func renderSourceMailboxMessageList(w http.ResponseWriter, account Account, folder string, messages []RawMessage) { + fmt.Fprintf(w, `
%s / %s (%d)
`, html.EscapeString(account.SrcUser), html.EscapeString(folder), len(messages)) + for i, raw := range messages { + subject := "(ohne Betreff)" + from := "(ohne Absender)" + date := "" + if msg, err := mail.ReadMessage(bytes.NewReader(raw.Body)); err == nil { + if v := decodeHeader(msg.Header.Get("Subject")); v != "" { + subject = v + } + if v := decodeHeader(msg.Header.Get("From")); v != "" { + from = v + } + date = decodeHeader(msg.Header.Get("Date")) + } + fmt.Fprintf(w, `%s%s%s`, + html.EscapeString(account.Name), html.EscapeString(folder), i, + urlEsc(account.Name), urlEsc(folder), i, + html.EscapeString(from), html.EscapeString(subject), html.EscapeString(date)) + } + if len(messages) == 0 { + fmt.Fprint(w, `
Keine Nachrichten in diesem Quell-Ordner.
`) } }