Files
EMLy/app.go
2026-02-05 22:41:02 +01:00

180 lines
5.7 KiB
Go

// Package main provides the core EMLy application.
// EMLy is a desktop email viewer for .eml and .msg files built with Wails v2.
package main
import (
"context"
"os"
"strings"
"sync"
"emly/backend/utils"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// =============================================================================
// App - Core Application Structure
// =============================================================================
// App is the main application struct that holds the application state and
// provides methods that are exposed to the frontend via Wails bindings.
//
// The struct manages:
// - Application context for Wails runtime calls
// - File paths for startup and currently loaded emails
// - Tracking of open viewer windows to prevent duplicates
type App struct {
// ctx is the Wails application context, used for runtime calls like dialogs
ctx context.Context
// StartupFilePath is set when the app is launched with an email file argument
StartupFilePath string
// CurrentMailFilePath tracks the currently loaded mail file path
// Used for bug reports to include the relevant email file
CurrentMailFilePath string
// openImages tracks which images are currently open in viewer windows
// The key is the filename, preventing duplicate viewers for the same file
openImagesMux sync.Mutex
openImages map[string]bool
// openPDFs tracks which PDFs are currently open in viewer windows
openPDFsMux sync.Mutex
openPDFs map[string]bool
// openEMLs tracks which EML attachments are currently open in viewer windows
openEMLsMux sync.Mutex
openEMLs map[string]bool
}
// =============================================================================
// Constructor & Lifecycle
// =============================================================================
// NewApp creates and initializes a new App instance.
// This is called from main.go before the Wails application starts.
func NewApp() *App {
return &App{
openImages: make(map[string]bool),
openPDFs: make(map[string]bool),
openEMLs: make(map[string]bool),
}
}
// startup is called by Wails when the application starts.
// It receives the application context which is required for Wails runtime calls.
//
// This method:
// - Saves the context for later use
// - Syncs CurrentMailFilePath with StartupFilePath if a file was opened via CLI
// - Logs the startup mode (main app vs viewer window)
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
// Sync CurrentMailFilePath with StartupFilePath if a file was opened via command line
if a.StartupFilePath != "" {
a.CurrentMailFilePath = a.StartupFilePath
}
// Check if this instance is running as a viewer (image/PDF) rather than main app
isViewer := false
for _, arg := range os.Args {
if strings.Contains(arg, "--view-image") || strings.Contains(arg, "--view-pdf") {
isViewer = true
break
}
}
if isViewer {
Log("Viewer instance started")
} else {
Log("EMLy main application started")
}
}
// shutdown is called by Wails when the application is closing.
// Used for cleanup operations.
func (a *App) shutdown(ctx context.Context) {
// Best-effort cleanup - currently no resources require explicit cleanup
}
// QuitApp terminates the application.
// It first calls Wails Quit to properly close the window,
// then forces an exit with a specific code.
func (a *App) QuitApp() {
runtime.Quit(a.ctx)
// Exit with code 133 (133 + 5 = 138, SIGTRAP-like exit)
os.Exit(133)
}
// =============================================================================
// Configuration Management
// =============================================================================
// GetConfig loads and returns the application configuration from config.ini.
// Returns nil if the configuration cannot be loaded.
func (a *App) GetConfig() *utils.Config {
cfgPath := utils.DefaultConfigPath()
cfg, err := utils.LoadConfig(cfgPath)
if err != nil {
Log("Failed to load config:", err)
return nil
}
return cfg
}
// SaveConfig persists the provided configuration to config.ini.
// Returns an error if saving fails.
func (a *App) SaveConfig(cfg *utils.Config) error {
cfgPath := utils.DefaultConfigPath()
if err := utils.SaveConfig(cfgPath, cfg); err != nil {
Log("Failed to save config:", err)
return err
}
return nil
}
// =============================================================================
// Startup File Management
// =============================================================================
// GetStartupFile returns the file path if the app was launched with an email file argument.
// Returns an empty string if no file was specified at startup.
func (a *App) GetStartupFile() string {
return a.StartupFilePath
}
// SetCurrentMailFilePath updates the path of the currently loaded mail file.
// This is called when the user opens a file via the file dialog.
func (a *App) SetCurrentMailFilePath(filePath string) {
a.CurrentMailFilePath = filePath
}
// GetCurrentMailFilePath returns the path of the currently loaded mail file.
// Used by bug reports to include the relevant email file.
func (a *App) GetCurrentMailFilePath() string {
return a.CurrentMailFilePath
}
// =============================================================================
// System Information
// =============================================================================
// GetMachineData retrieves system information about the current machine.
// Returns hostname, OS version, hardware ID, etc.
func (a *App) GetMachineData() *utils.MachineInfo {
data, _ := utils.GetMachineInfo()
return data
}
// IsDebuggerRunning checks if a debugger is attached to the application.
// Used for anti-debugging protection in production builds.
func (a *App) IsDebuggerRunning() bool {
if a == nil {
return false
}
return utils.IsDebugged()
}