Compare commits
8 Commits
e7d1850a63
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad1116db14 | ||
|
|
7cfc12c6ef | ||
|
|
e9b013412a | ||
|
|
671f5aa8aa | ||
|
|
3fb2f95e8a | ||
|
|
654475d3ea | ||
|
|
3c24421c8c | ||
|
|
1e84320588 |
13
app.go
13
app.go
@@ -44,8 +44,21 @@ func NewApp() *App {
|
|||||||
// so we can call the runtime methods
|
// so we can call the runtime methods
|
||||||
func (a *App) startup(ctx context.Context) {
|
func (a *App) startup(ctx context.Context) {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
|
|
||||||
|
isViewer := false
|
||||||
|
for _, arg := range os.Args {
|
||||||
|
if strings.Contains(arg, "--view-image") || strings.Contains(arg, "--view-pdf") {
|
||||||
|
isViewer = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isViewer {
|
||||||
|
Log("Second instance launch")
|
||||||
|
} else {
|
||||||
Log("Wails startup")
|
Log("Wails startup")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) GetConfig() *utils.Config {
|
func (a *App) GetConfig() *utils.Config {
|
||||||
cfgPath := utils.DefaultConfigPath()
|
cfgPath := utils.DefaultConfigPath()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package internal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
@@ -58,10 +59,68 @@ func ReadEmlFile(filePath string) (*EmailData, error) {
|
|||||||
body = email.TextBody
|
body = email.TextBody
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process attachments and detect PEC
|
// Process attachments list and PEC detection
|
||||||
var attachments []EmailAttachment
|
var attachments []EmailAttachment
|
||||||
var hasDatiCert, hasSmime, hasInnerEmail bool
|
var hasDatiCert, hasSmime, hasInnerEmail bool
|
||||||
|
|
||||||
|
// Process embedded files (inline images) -> add to body AND add as attachments
|
||||||
|
for _, ef := range email.EmbeddedFiles {
|
||||||
|
data, err := io.ReadAll(ef.Data)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to base64
|
||||||
|
b64 := base64.StdEncoding.EncodeToString(data)
|
||||||
|
mimeType := ef.ContentType
|
||||||
|
if parts := strings.Split(mimeType, ";"); len(parts) > 0 {
|
||||||
|
mimeType = strings.TrimSpace(parts[0])
|
||||||
|
}
|
||||||
|
if mimeType == "" {
|
||||||
|
mimeType = "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create data URI
|
||||||
|
dataURI := fmt.Sprintf("data:%s;base64,%s", mimeType, b64)
|
||||||
|
|
||||||
|
// Replace cid:reference with data URI in HTML body
|
||||||
|
// ef.CID is already trimmed of <>
|
||||||
|
target := "cid:" + ef.CID
|
||||||
|
body = strings.ReplaceAll(body, target, dataURI)
|
||||||
|
|
||||||
|
// ALSO ADD AS ATTACHMENTS for the viewer
|
||||||
|
filename := ef.CID
|
||||||
|
if filename == "" {
|
||||||
|
filename = "embedded_image"
|
||||||
|
}
|
||||||
|
// If no extension, try to infer from mimetype
|
||||||
|
if !strings.Contains(filename, ".") {
|
||||||
|
ext := "dat"
|
||||||
|
switch mimeType {
|
||||||
|
case "image/jpeg":
|
||||||
|
ext = "jpg"
|
||||||
|
case "image/png":
|
||||||
|
ext = "png"
|
||||||
|
case "image/gif":
|
||||||
|
ext = "gif"
|
||||||
|
case "application/pdf":
|
||||||
|
ext = "pdf"
|
||||||
|
default:
|
||||||
|
if parts := strings.Split(mimeType, "/"); len(parts) > 1 {
|
||||||
|
ext = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filename = fmt.Sprintf("%s.%s", filename, ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments = append(attachments, EmailAttachment{
|
||||||
|
Filename: filename,
|
||||||
|
ContentType: mimeType,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process standard attachments
|
||||||
for _, att := range email.Attachments {
|
for _, att := range email.Attachments {
|
||||||
data, err := io.ReadAll(att.Data)
|
data, err := io.ReadAll(att.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[EMLy]
|
[EMLy]
|
||||||
SDK_DECODER_SEMVER="1.3.0"
|
SDK_DECODER_SEMVER="1.3.1"
|
||||||
SDK_DECODER_RELEASE_CHANNEL="beta"
|
SDK_DECODER_RELEASE_CHANNEL="beta"
|
||||||
GUI_SEMVER="1.2.4"
|
GUI_SEMVER="1.3.0"
|
||||||
GUI_RELEASE_CHANNEL="beta"
|
GUI_RELEASE_CHANNEL="beta"
|
||||||
LANGUAGE="it"
|
LANGUAGE="it"
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
import { mailState } from "$lib/stores/mail-state.svelte";
|
import { mailState } from "$lib/stores/mail-state.svelte";
|
||||||
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";
|
||||||
|
|
||||||
let unregisterEvents = () => {};
|
let unregisterEvents = () => {};
|
||||||
let isLoading = $state(false);
|
let isLoading = $state(false);
|
||||||
@@ -22,11 +23,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
console.log("Current email changed:", mailState.currentEmail);
|
if(dev) {
|
||||||
|
console.log(mailState.currentEmail)
|
||||||
|
}
|
||||||
|
console.info("Current email changed:", mailState.currentEmail?.subject);
|
||||||
if(mailState.currentEmail !== null) {
|
if(mailState.currentEmail !== null) {
|
||||||
sidebarOpen.set(false);
|
sidebarOpen.set(false);
|
||||||
}
|
}
|
||||||
console.log(mailState.currentEmail?.attachments)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
56
frontend/src/lib/utils/logger-hook.ts
Normal file
56
frontend/src/lib/utils/logger-hook.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { FrontendLog } from '$lib/wailsjs/go/main/App';
|
||||||
|
|
||||||
|
function safeStringify(obj: any): string {
|
||||||
|
try {
|
||||||
|
if (typeof obj === 'object' && obj !== null) {
|
||||||
|
return JSON.stringify(obj);
|
||||||
|
}
|
||||||
|
return String(obj);
|
||||||
|
} catch (e) {
|
||||||
|
return '[Circular/Error]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setupConsoleLogger() {
|
||||||
|
if ((window as any).__logger_initialized__) return;
|
||||||
|
(window as any).__logger_initialized__ = true;
|
||||||
|
|
||||||
|
const originalLog = console.log;
|
||||||
|
const originalWarn = console.warn;
|
||||||
|
const originalError = console.error;
|
||||||
|
const originalInfo = console.info;
|
||||||
|
|
||||||
|
function logToBackend(level: string, args: any[]) {
|
||||||
|
try {
|
||||||
|
// Avoid logging if wails runtime is not ready or function is missing
|
||||||
|
if (typeof FrontendLog !== 'function') return;
|
||||||
|
|
||||||
|
const message = args.map(arg => safeStringify(arg)).join(' ');
|
||||||
|
FrontendLog(level, message).catch(() => {});
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log = (...args) => {
|
||||||
|
originalLog(...args);
|
||||||
|
logToBackend("INFO", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.warn = (...args) => {
|
||||||
|
originalWarn(...args);
|
||||||
|
logToBackend("WARN", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.error = (...args) => {
|
||||||
|
originalError(...args);
|
||||||
|
logToBackend("ERROR", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
console.info = (...args) => {
|
||||||
|
originalInfo(...args);
|
||||||
|
logToBackend("INFO", args);
|
||||||
|
};
|
||||||
|
|
||||||
|
originalLog("Console logger hooked to Wails backend");
|
||||||
|
}
|
||||||
2
frontend/src/lib/wailsjs/go/main/App.d.ts
vendored
2
frontend/src/lib/wailsjs/go/main/App.d.ts
vendored
@@ -6,6 +6,8 @@ import {internal} from '../models';
|
|||||||
|
|
||||||
export function CheckIsDefaultEMLHandler():Promise<boolean>;
|
export function CheckIsDefaultEMLHandler():Promise<boolean>;
|
||||||
|
|
||||||
|
export function FrontendLog(arg1:string,arg2:string):Promise<void>;
|
||||||
|
|
||||||
export function GetConfig():Promise<utils.Config>;
|
export function GetConfig():Promise<utils.Config>;
|
||||||
|
|
||||||
export function GetImageViewerData():Promise<main.ImageViewerData>;
|
export function GetImageViewerData():Promise<main.ImageViewerData>;
|
||||||
|
|||||||
@@ -3,85 +3,89 @@
|
|||||||
// This file is automatically generated. DO NOT EDIT
|
// This file is automatically generated. DO NOT EDIT
|
||||||
|
|
||||||
export function CheckIsDefaultEMLHandler() {
|
export function CheckIsDefaultEMLHandler() {
|
||||||
return ObfuscatedCall(0, []);
|
return window['go']['main']['App']['CheckIsDefaultEMLHandler']();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FrontendLog(arg1, arg2) {
|
||||||
|
return window['go']['main']['App']['FrontendLog'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetConfig() {
|
export function GetConfig() {
|
||||||
return ObfuscatedCall(1, []);
|
return window['go']['main']['App']['GetConfig']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetImageViewerData() {
|
export function GetImageViewerData() {
|
||||||
return ObfuscatedCall(2, []);
|
return window['go']['main']['App']['GetImageViewerData']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetMachineData() {
|
export function GetMachineData() {
|
||||||
return ObfuscatedCall(3, []);
|
return window['go']['main']['App']['GetMachineData']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetPDFViewerData() {
|
export function GetPDFViewerData() {
|
||||||
return ObfuscatedCall(4, []);
|
return window['go']['main']['App']['GetPDFViewerData']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetStartupFile() {
|
export function GetStartupFile() {
|
||||||
return ObfuscatedCall(5, []);
|
return window['go']['main']['App']['GetStartupFile']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetViewerData() {
|
export function GetViewerData() {
|
||||||
return ObfuscatedCall(6, []);
|
return window['go']['main']['App']['GetViewerData']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IsDebuggerRunning() {
|
export function IsDebuggerRunning() {
|
||||||
return ObfuscatedCall(7, []);
|
return window['go']['main']['App']['IsDebuggerRunning']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenDefaultAppsSettings() {
|
export function OpenDefaultAppsSettings() {
|
||||||
return ObfuscatedCall(8, []);
|
return window['go']['main']['App']['OpenDefaultAppsSettings']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenEMLWindow(arg1, arg2) {
|
export function OpenEMLWindow(arg1, arg2) {
|
||||||
return ObfuscatedCall(9, [arg1, arg2]);
|
return window['go']['main']['App']['OpenEMLWindow'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenImage(arg1, arg2) {
|
export function OpenImage(arg1, arg2) {
|
||||||
return ObfuscatedCall(10, [arg1, arg2]);
|
return window['go']['main']['App']['OpenImage'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenImageWindow(arg1, arg2) {
|
export function OpenImageWindow(arg1, arg2) {
|
||||||
return ObfuscatedCall(11, [arg1, arg2]);
|
return window['go']['main']['App']['OpenImageWindow'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenPDF(arg1, arg2) {
|
export function OpenPDF(arg1, arg2) {
|
||||||
return ObfuscatedCall(12, [arg1, arg2]);
|
return window['go']['main']['App']['OpenPDF'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenPDFWindow(arg1, arg2) {
|
export function OpenPDFWindow(arg1, arg2) {
|
||||||
return ObfuscatedCall(13, [arg1, arg2]);
|
return window['go']['main']['App']['OpenPDFWindow'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function QuitApp() {
|
export function QuitApp() {
|
||||||
return ObfuscatedCall(14, []);
|
return window['go']['main']['App']['QuitApp']();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReadEML(arg1) {
|
export function ReadEML(arg1) {
|
||||||
return ObfuscatedCall(15, [arg1]);
|
return window['go']['main']['App']['ReadEML'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReadMSG(arg1, arg2) {
|
export function ReadMSG(arg1, arg2) {
|
||||||
return ObfuscatedCall(16, [arg1, arg2]);
|
return window['go']['main']['App']['ReadMSG'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReadMSGOSS(arg1) {
|
export function ReadMSGOSS(arg1) {
|
||||||
return ObfuscatedCall(17, [arg1]);
|
return window['go']['main']['App']['ReadMSGOSS'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReadPEC(arg1) {
|
export function ReadPEC(arg1) {
|
||||||
return ObfuscatedCall(18, [arg1]);
|
return window['go']['main']['App']['ReadPEC'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SaveConfig(arg1) {
|
export function SaveConfig(arg1) {
|
||||||
return ObfuscatedCall(19, [arg1]);
|
return window['go']['main']['App']['SaveConfig'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ShowOpenFileDialog() {
|
export function ShowOpenFileDialog() {
|
||||||
return ObfuscatedCall(20, []);
|
return window['go']['main']['App']['ShowOpenFileDialog']();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,10 +31,12 @@
|
|||||||
} from "$lib/wailsjs/runtime/runtime";
|
} from "$lib/wailsjs/runtime/runtime";
|
||||||
import { RefreshCcwDot } from "@lucide/svelte";
|
import { RefreshCcwDot } from "@lucide/svelte";
|
||||||
import { IsDebuggerRunning, QuitApp } from "$lib/wailsjs/go/main/App";
|
import { IsDebuggerRunning, QuitApp } from "$lib/wailsjs/go/main/App";
|
||||||
|
import { settingsStore } from "$lib/stores/settings.svelte.js";
|
||||||
|
|
||||||
let versionInfo: utils.Config | null = $state(null);
|
let versionInfo: utils.Config | null = $state(null);
|
||||||
let isMaximized = $state(false);
|
let isMaximized = $state(false);
|
||||||
let isDebugerOn: boolean = $state(false);
|
let isDebugerOn: boolean = $state(false);
|
||||||
|
let isDebbugerProtectionOn: boolean = $state(true);
|
||||||
|
|
||||||
async function syncMaxState() {
|
async function syncMaxState() {
|
||||||
isMaximized = await WindowIsMaximised();
|
isMaximized = await WindowIsMaximised();
|
||||||
@@ -69,7 +71,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (browser) {
|
if (browser && isDebbugerProtectionOn) {
|
||||||
detectDebugging();
|
detectDebugging();
|
||||||
setInterval(detectDebugging, 1000);
|
setInterval(detectDebugging, 1000);
|
||||||
}
|
}
|
||||||
@@ -118,6 +120,8 @@
|
|||||||
} catch {
|
} catch {
|
||||||
stored = null;
|
stored = null;
|
||||||
}
|
}
|
||||||
|
isDebbugerProtectionOn = settingsStore.settings.enableAttachedDebuggerProtection ? true : false;
|
||||||
|
$inspect(isDebbugerProtectionOn, "isDebbugerProtectionOn");
|
||||||
|
|
||||||
applyTheme(stored === "light" ? "light" : "dark");
|
applyTheme(stored === "light" ? "light" : "dark");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import MailViewer from "$lib/components/dashboard/MailViewer.svelte";
|
import MailViewer from "$lib/components/MailViewer.svelte";
|
||||||
import { mailState } from "$lib/stores/mail-state.svelte";
|
import { mailState } from "$lib/stores/mail-state.svelte";
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { redirect } from '@sveltejs/kit';
|
|||||||
import type { PageLoad } from './$types';
|
import type { PageLoad } from './$types';
|
||||||
import { GetViewerData, GetStartupFile, ReadEML, ReadMSG } from '$lib/wailsjs/go/main/App';
|
import { GetViewerData, GetStartupFile, ReadEML, ReadMSG } from '$lib/wailsjs/go/main/App';
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import { settingsStore } from '$lib/stores/settings.svelte';
|
|
||||||
import type { internal } from '$lib/wailsjs/go/models';
|
import type { internal } from '$lib/wailsjs/go/models';
|
||||||
|
|
||||||
export const load: PageLoad = async () => {
|
export const load: PageLoad = async () => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { Label } from "$lib/components/ui/label";
|
import { Label } from "$lib/components/ui/label";
|
||||||
import { Separator } from "$lib/components/ui/separator";
|
import { Separator } from "$lib/components/ui/separator";
|
||||||
import { Switch } from "$lib/components/ui/switch";
|
import { Switch } from "$lib/components/ui/switch";
|
||||||
import { ChevronLeft, Command, Option, Flame } from "@lucide/svelte";
|
import { ChevronLeft, Flame } from "@lucide/svelte";
|
||||||
import type { EMLy_GUI_Settings } from "$lib/types";
|
import type { EMLy_GUI_Settings } from "$lib/types";
|
||||||
import { toast } from "svelte-sonner";
|
import { toast } from "svelte-sonner";
|
||||||
import { It, Us } from "svelte-flags";
|
import { It, Us } from "svelte-flags";
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { setupConsoleLogger } from '$lib/utils/logger-hook';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
setupConsoleLogger();
|
||||||
const loader = document.getElementById('app-loading');
|
const loader = document.getElementById('app-loading');
|
||||||
if (loader) {
|
if (loader) {
|
||||||
loader.style.opacity = '0';
|
loader.style.opacity = '0';
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
|
#define ApplicationName 'EMLy'
|
||||||
|
#define ApplicationVersion GetVersionNumbersString('EMLy.exe')
|
||||||
|
#define ApplicationVersion '1.2.4_beta'
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppName=EMLy
|
AppName={#ApplicationName}
|
||||||
AppVersion=1.2.2
|
AppVersion={#ApplicationVersion}
|
||||||
DefaultDirName={autopf}\EMLy
|
DefaultDirName={autopf}\EMLy
|
||||||
OutputBaseFilename=EMLy_Installer_1.2.2
|
OutputBaseFilename={#ApplicationName}_Installer_{#ApplicationVersion}
|
||||||
ArchitecturesInstallIn64BitMode=x64compatible
|
ArchitecturesInstallIn64BitMode=x64compatible
|
||||||
DisableProgramGroupPage=yes
|
DisableProgramGroupPage=yes
|
||||||
; Request administrative privileges for HKA to write to HKLM if needed,
|
; Request administrative privileges for HKA to write to HKLM if needed,
|
||||||
; or use "lowest" if purely per-user, but file associations usually work better with admin rights or proper HKA handling.
|
; or use "lowest" if purely per-user, but file associations usually work better with admin rights or proper HKA handling.
|
||||||
PrivilegesRequired=admin
|
PrivilegesRequired=admin
|
||||||
SetupIconFile=..\build\windows\icon.ico
|
SetupIconFile=..\build\windows\icon.ico
|
||||||
UninstallDisplayIcon={app}\EMLy.exe
|
UninstallDisplayIcon={app}\{#ApplicationName}.exe
|
||||||
|
AppVerName={#ApplicationName} {#ApplicationVersion}
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; Source path relative to this .iss file (assuming it is in the "installer" folder and build is in "../build")
|
; Source path relative to this .iss file (assuming it is in the "installer" folder and build is in "../build")
|
||||||
Source: "..\build\bin\EMLy.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\build\bin\{#ApplicationName}.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "..\build\bin\config.ini"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "..\build\bin\config.ini"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "..\build\bin\signed_msg.exe"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
|
|
||||||
[Registry]
|
[Registry]
|
||||||
; 1. Register the .eml extension and point it to our internal ProgID "EMLy.EML"
|
; 1. Register the .eml extension and point it to our internal ProgID "EMLy.EML"
|
||||||
Root: HKA; Subkey: "Software\Classes\.eml"; ValueType: string; ValueName: ""; ValueData: "EMLy.EML"; Flags: uninsdeletevalue
|
Root: HKA; Subkey: "Software\Classes\.eml"; ValueType: string; ValueName: ""; ValueData: "{#ApplicationName}.EML"; Flags: uninsdeletevalue
|
||||||
Root: HKA; Subkey: "Software\Classes\.msg"; ValueType: string; ValueName: ""; ValueData: "EMLy.MSG"; Flags: uninsdeletevalue
|
Root: HKA; Subkey: "Software\Classes\.msg"; ValueType: string; ValueName: ""; ValueData: "{#ApplicationName}.MSG"; Flags: uninsdeletevalue
|
||||||
|
|
||||||
; 2. Define the ProgID with a readable name and icon
|
; 2. Define the ProgID with a readable name and icon
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.EML"; ValueType: string; ValueName: ""; ValueData: "EMLy Email Message"; Flags: uninsdeletekey
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.EML"; ValueType: string; ValueName: ""; ValueData: "{#ApplicationName} Email Message"; Flags: uninsdeletekey
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.EML\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\EMLy.exe,0"
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.EML\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#ApplicationName}.exe,0"
|
||||||
|
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.MSG"; ValueType: string; ValueName: ""; ValueData: "EMLy Outlook Message"; Flags: uninsdeletekey
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.MSG"; ValueType: string; ValueName: ""; ValueData: "{#ApplicationName} Outlook Message"; Flags: uninsdeletekey
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.MSG\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\EMLy.exe,0"
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.MSG\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#ApplicationName}.exe,0"
|
||||||
|
|
||||||
; 3. Define the open command
|
; 3. Define the open command
|
||||||
; "%1" passes the file path to the application
|
; "%1" passes the file path to the application
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.EML\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\EMLy.exe"" ""%1"""
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.EML\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\EMLy.exe"" ""%1"""
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.MSG\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\EMLy.exe"" ""%1"""
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.MSG\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\EMLy.exe"" ""%1"""
|
||||||
|
|
||||||
; Optional: Add "Open with EMLy" to context menu explicitly (though file association typically handles the double click)
|
; Optional: Add "Open with EMLy" to context menu explicitly (though file association typically handles the double click)
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.EML\shell\open"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "EMLy"
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.EML\shell\open"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "{#ApplicationName}"
|
||||||
Root: HKA; Subkey: "Software\Classes\EMLy.MSG\shell\open"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "EMLy"
|
Root: HKA; Subkey: "Software\Classes\{#ApplicationName}.MSG\shell\open"; ValueType: string; ValueName: "FriendlyAppName"; ValueData: "{#ApplicationName}"
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{autoprograms}\EMLy"; Filename: "{app}\EMLy.exe"
|
Name: "{autoprograms}\{#ApplicationName}"; Filename: "{app}\{#ApplicationName}.exe"
|
||||||
|
|||||||
54
logger.go
54
logger.go
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -10,7 +11,47 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var logger = log.New(os.Stdout, "", 0)
|
var (
|
||||||
|
logger = log.New(os.Stdout, "", 0)
|
||||||
|
logFile *os.File
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitLogger initializes the logger to write to both stdout and a file in AppData
|
||||||
|
func InitLogger() error {
|
||||||
|
configDir, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
appDir := filepath.Join(configDir, "EMLy")
|
||||||
|
logsDir := filepath.Join(appDir, "logs")
|
||||||
|
|
||||||
|
if err := os.MkdirAll(logsDir, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath := filepath.Join(logsDir, "app.log")
|
||||||
|
// Open file in Append mode
|
||||||
|
file, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logFile = file
|
||||||
|
|
||||||
|
// MultiWriter to write to both stdout and file
|
||||||
|
multi := io.MultiWriter(os.Stdout, file)
|
||||||
|
logger = log.New(multi, "", 0)
|
||||||
|
|
||||||
|
Log("Logger initialized. Writing to: " + logPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseLogger closes the log file
|
||||||
|
func CloseLogger() {
|
||||||
|
if logFile != nil {
|
||||||
|
logFile.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Log prints a timestamped, file:line tagged log line.
|
// Log prints a timestamped, file:line tagged log line.
|
||||||
func Log(args ...any) {
|
func Log(args ...any) {
|
||||||
@@ -27,3 +68,14 @@ func Log(args ...any) {
|
|||||||
msg := fmt.Sprintln(args...)
|
msg := fmt.Sprintln(args...)
|
||||||
logger.Printf("[%s] - [%s] - [%s] - %s", date, tm, loc, strings.TrimRight(msg, "\n"))
|
logger.Printf("[%s] - [%s] - [%s] - %s", date, tm, loc, strings.TrimRight(msg, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FrontendLog allows the frontend to send logs to the backend logger
|
||||||
|
func (a *App) FrontendLog(level string, message string) {
|
||||||
|
now := time.Now()
|
||||||
|
date := now.Format("2006-01-02")
|
||||||
|
tm := now.Format("15:04:05")
|
||||||
|
|
||||||
|
// We don't use runtime.Caller here because it would point to this function
|
||||||
|
// Instead we tag it as [FRONTEND]
|
||||||
|
logger.Printf("[%s] - [%s] - [FRONTEND] - [%s] %s", date, tm, level, message)
|
||||||
|
}
|
||||||
|
|||||||
5
main.go
5
main.go
@@ -28,6 +28,11 @@ func (a *App) onSecondInstanceLaunch(secondInstanceData options.SecondInstanceDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if err := InitLogger(); err != nil {
|
||||||
|
log.Println("Error initializing logger:", err)
|
||||||
|
}
|
||||||
|
defer CloseLogger()
|
||||||
|
|
||||||
// Check for custom args
|
// Check for custom args
|
||||||
args := os.Args
|
args := os.Args
|
||||||
uniqueId := "emly-app-lock"
|
uniqueId := "emly-app-lock"
|
||||||
|
|||||||
Reference in New Issue
Block a user