feat: add UTF-8 conversion for email body and enhance MailViewer processing

This commit is contained in:
Lyz Coote
2026-02-05 15:26:52 +01:00
parent ad1116db14
commit d9e848d3f4
5 changed files with 79 additions and 11 deletions

17
app.go
View File

@@ -10,8 +10,11 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"unicode/utf8"
"golang.org/x/sys/windows/registry" "golang.org/x/sys/windows/registry"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/transform"
"emly/backend/utils" "emly/backend/utils"
internal "emly/backend/utils/mail" internal "emly/backend/utils/mail"
@@ -517,3 +520,17 @@ func (a *App) IsDebuggerRunning() bool {
} }
return utils.IsDebugged() return utils.IsDebugged()
} }
func (a *App) ConvertToUTF8(s string) string {
if utf8.ValidString(s) {
return s
}
// If invalid UTF-8, assume Windows-1252 (superset of ISO-8859-1)
decoder := charmap.Windows1252.NewDecoder()
decoded, _, err := transform.String(decoder, s)
if err != nil {
return s // Return as-is if decoding fails
}
return decoded
}

View File

@@ -1,6 +1,6 @@
[EMLy] [EMLy]
SDK_DECODER_SEMVER="1.3.1" SDK_DECODER_SEMVER="1.3.1"
SDK_DECODER_RELEASE_CHANNEL="beta" SDK_DECODER_RELEASE_CHANNEL="beta"
GUI_SEMVER="1.3.0" GUI_SEMVER="1.3.1"
GUI_RELEASE_CHANNEL="beta" GUI_RELEASE_CHANNEL="beta"
LANGUAGE="it" LANGUAGE="it"

View File

@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { X, MailOpen, Image, FileText, File, ShieldCheck, Shield, Signature, FileCode, Loader2 } from "@lucide/svelte"; import { X, MailOpen, Image, FileText, File, ShieldCheck, Shield, Signature, FileCode, Loader2 } from "@lucide/svelte";
import { ShowOpenFileDialog, ReadEML, OpenPDF, OpenImageWindow, OpenPDFWindow, OpenImage, ReadMSG, ReadPEC, OpenEMLWindow } from "$lib/wailsjs/go/main/App"; import { ShowOpenFileDialog, ReadEML, OpenPDF, OpenImageWindow, OpenPDFWindow, OpenImage, ReadMSG, ReadPEC, OpenEMLWindow, ConvertToUTF8 } from "$lib/wailsjs/go/main/App";
import type { internal } from "$lib/wailsjs/go/models"; import type { internal } from "$lib/wailsjs/go/models";
import { sidebarOpen } from "$lib/stores/app"; import { sidebarOpen } from "$lib/stores/app";
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
@@ -10,6 +10,7 @@
import { settingsStore } from "$lib/stores/settings.svelte"; import { settingsStore } from "$lib/stores/settings.svelte";
import * as m from "$lib/paraglide/messages"; import * as m from "$lib/paraglide/messages";
import { dev } from "$app/environment"; import { dev } from "$app/environment";
import { isBase64, isHtml } from "$lib/utils";
let unregisterEvents = () => {}; let unregisterEvents = () => {};
let isLoading = $state(false); let isLoading = $state(false);
@@ -23,13 +24,49 @@
} }
$effect(() => { $effect(() => {
if(dev) { const process = async () => {
console.log(mailState.currentEmail) if (mailState.currentEmail?.body) {
} let content = mailState.currentEmail.body;
console.info("Current email changed:", mailState.currentEmail?.subject); // 1. Try to decode if not HTML
if(mailState.currentEmail !== null) { if (!isHtml(content)) {
sidebarOpen.set(false); const clean = content.replace(/[\s\r\n]+/g, '');
} if (isBase64(clean)) {
try {
const decoded = window.atob(clean);
content = decoded;
} catch (e) {
console.warn("Failed to decode base64 body:", e);
}
}
}
// 2. If it is HTML (original or decoded), try to fix encoding
if (isHtml(content)) {
try {
const fixed = await ConvertToUTF8(content);
if (fixed) {
content = fixed;
}
} catch (e) {
console.warn("Failed to fix encoding:", e);
}
}
// 3. Update if changed
if (content !== mailState.currentEmail.body) {
mailState.currentEmail.body = content;
}
}
if(dev) {
console.log(mailState.currentEmail)
}
console.info("Current email changed:", mailState.currentEmail?.subject);
if(mailState.currentEmail !== null) {
sidebarOpen.set(false);
}
};
process();
}) })
onDestroy(() => { onDestroy(() => {

View File

@@ -11,3 +11,17 @@ export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T; export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>; export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null }; export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
export function isBase64(str: string): boolean {
if (!str) return false;
const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
return base64Regex.test(str);
}
export function isHtml(str: string): boolean {
if (!str) return false;
const htmlRegex = /<[^>]+>/;
return htmlRegex.test(str);
}

View File

@@ -1,6 +1,6 @@
#define ApplicationName 'EMLy' #define ApplicationName 'EMLy'
#define ApplicationVersion GetVersionNumbersString('EMLy.exe') #define ApplicationVersion GetVersionNumbersString('EMLy.exe')
#define ApplicationVersion '1.2.4_beta' #define ApplicationVersion '1.3.1_beta'
[Setup] [Setup]
AppName={#ApplicationName} AppName={#ApplicationName}