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"
"sync"
"time"
"unicode/utf8"
"golang.org/x/sys/windows/registry"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/transform"
"emly/backend/utils"
internal "emly/backend/utils/mail"
@@ -517,3 +520,17 @@ func (a *App) IsDebuggerRunning() bool {
}
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]
SDK_DECODER_SEMVER="1.3.1"
SDK_DECODER_RELEASE_CHANNEL="beta"
GUI_SEMVER="1.3.0"
GUI_SEMVER="1.3.1"
GUI_RELEASE_CHANNEL="beta"
LANGUAGE="it"

View File

@@ -1,6 +1,6 @@
<script lang="ts">
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 { sidebarOpen } from "$lib/stores/app";
import { onDestroy, onMount } from "svelte";
@@ -10,6 +10,7 @@
import { settingsStore } from "$lib/stores/settings.svelte";
import * as m from "$lib/paraglide/messages";
import { dev } from "$app/environment";
import { isBase64, isHtml } from "$lib/utils";
let unregisterEvents = () => {};
let isLoading = $state(false);
@@ -23,6 +24,40 @@
}
$effect(() => {
const process = async () => {
if (mailState.currentEmail?.body) {
let content = mailState.currentEmail.body;
// 1. Try to decode if not HTML
if (!isHtml(content)) {
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)
}
@@ -30,6 +65,8 @@
if(mailState.currentEmail !== null) {
sidebarOpen.set(false);
}
};
process();
})
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 WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
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 ApplicationVersion GetVersionNumbersString('EMLy.exe')
#define ApplicationVersion '1.2.4_beta'
#define ApplicationVersion '1.3.1_beta'
[Setup]
AppName={#ApplicationName}