From 72dda149a9a86a5bc1e3b79aaccbc12917e49540 Mon Sep 17 00:00:00 2001 From: Wellington Ribeiro Date: Fri, 20 Mar 2026 22:47:28 +0000 Subject: [PATCH] Adjusting multiple popups and general refactoring --- OutlookCaseHelper/Form1.cs | 752 ++++++++++------------------- OutlookCaseHelper/OutlookHelper.cs | 599 +++++++++-------------- 2 files changed, 496 insertions(+), 855 deletions(-) diff --git a/OutlookCaseHelper/Form1.cs b/OutlookCaseHelper/Form1.cs index 7815531..4832685 100644 --- a/OutlookCaseHelper/Form1.cs +++ b/OutlookCaseHelper/Form1.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Win32; +using Outlook = Microsoft.Office.Interop.Outlook; namespace OutlookCaseHelper { @@ -24,21 +25,24 @@ namespace OutlookCaseHelper private NotifyIcon trayIcon = null!; private ContextMenuStrip trayMenu = null!; - private OutlookHelper outlookHelper; + private readonly OutlookHelper outlookHelper; private System.Windows.Forms.Timer monitorTimer = null!; private uint hotkeyCreateMod = MOD_ALT; - private uint hotkeyCreateKey = (uint)Keys.F1; + private uint hotkeyCreateKey = (uint)Keys.D1; private uint hotkeyRemoveMod = MOD_ALT; - private uint hotkeyRemoveKey = (uint)Keys.F2; + private uint hotkeyRemoveKey = (uint)Keys.D2; private readonly string settingsPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "OutlookCaseHelper", "hotkeys.json"); - // Singleton para janelas abertas private DashboardForm? _dashboardForm; private HotkeySettingsForm? _settingsForm; + private CreateRuleForm? _createRuleForm; + private InputForm? _removeRuleForm; + + // --- Constructor & Init --- public Form1() { @@ -54,72 +58,16 @@ namespace OutlookCaseHelper trayIcon.ShowBalloonTip(3000, "Outlook Case Manager", "App is running and monitoring your emails.", ToolTipIcon.Info); } - public void ReloadOutlookRules() + public void ReloadOutlookRules() => outlookHelper.ReloadRules(); + + private void InitializeTimer() { - outlookHelper.ReloadRules(); + monitorTimer = new System.Windows.Forms.Timer { Interval = 60000 }; + monitorTimer.Tick += (s, e) => { try { outlookHelper.ProcessActiveRules(); } catch { } }; + monitorTimer.Start(); } - private void SetStartupWithWindows(bool enable) - { - try - { - using var key = Registry.CurrentUser.OpenSubKey( - @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - if (key == null) return; - - if (enable) - key.SetValue("OutlookCaseHelper", - $"\"{System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName}\""); - else - key.DeleteValue("OutlookCaseHelper", false); - } - catch { } - } - - private void LoadHotkeySettings() - { - try - { - if (File.Exists(settingsPath)) - { - var json = File.ReadAllText(settingsPath); - var settings = JsonSerializer.Deserialize(json); - if (settings != null) - { - hotkeyCreateMod = settings.CreateMod; - hotkeyCreateKey = settings.CreateKey; - hotkeyRemoveMod = settings.RemoveMod; - hotkeyRemoveKey = settings.RemoveKey; - } - } - } - catch { } - } - - private void SaveHotkeySettings() - { - try - { - Directory.CreateDirectory(Path.GetDirectoryName(settingsPath)!); - var settings = new HotkeySettings - { - CreateMod = hotkeyCreateMod, - CreateKey = hotkeyCreateKey, - RemoveMod = hotkeyRemoveMod, - RemoveKey = hotkeyRemoveKey - }; - File.WriteAllText(settingsPath, JsonSerializer.Serialize(settings)); - } - catch { } - } - - private class HotkeySettings - { - public uint CreateMod { get; set; } - public uint CreateKey { get; set; } - public uint RemoveMod { get; set; } - public uint RemoveKey { get; set; } - } + // --- Hotkeys --- protected override void OnHandleCreated(EventArgs e) { @@ -144,18 +92,71 @@ namespace OutlookCaseHelper protected override void WndProc(ref Message m) { - const int WM_HOTKEY = 0x0312; - if (m.Msg == WM_HOTKEY) + if (m.Msg == 0x0312) { - int id = m.WParam.ToInt32(); - if (id == HOTKEY_CREATE) - ProcessEmail_Click(null, EventArgs.Empty); - else if (id == HOTKEY_REMOVE) - RemoveRuleFromSelected_Click(null, EventArgs.Empty); + if (m.WParam.ToInt32() == HOTKEY_CREATE) ProcessEmail_Click(null, EventArgs.Empty); + else if (m.WParam.ToInt32() == HOTKEY_REMOVE) RemoveRuleFromSelected_Click(null, EventArgs.Empty); } base.WndProc(ref m); } + private void LoadHotkeySettings() + { + try + { + if (!File.Exists(settingsPath)) return; + var settings = JsonSerializer.Deserialize(File.ReadAllText(settingsPath)); + if (settings == null) return; + hotkeyCreateMod = settings.CreateMod; + hotkeyCreateKey = settings.CreateKey; + hotkeyRemoveMod = settings.RemoveMod; + hotkeyRemoveKey = settings.RemoveKey; + } + catch { } + } + + private void SaveHotkeySettings() + { + try + { + Directory.CreateDirectory(Path.GetDirectoryName(settingsPath)!); + File.WriteAllText(settingsPath, JsonSerializer.Serialize(new HotkeySettings + { + CreateMod = hotkeyCreateMod, + CreateKey = hotkeyCreateKey, + RemoveMod = hotkeyRemoveMod, + RemoveKey = hotkeyRemoveKey + })); + } + catch { } + } + + private class HotkeySettings + { + public uint CreateMod { get; set; } + public uint CreateKey { get; set; } + public uint RemoveMod { get; set; } + public uint RemoveKey { get; set; } + } + + // --- Startup --- + + private void SetStartupWithWindows(bool enable) + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); + if (key == null) return; + if (enable) + key.SetValue("OutlookCaseHelper", $"\"{System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName}\""); + else + key.DeleteValue("OutlookCaseHelper", false); + } + catch { } + } + + // --- Tray --- + private void InitializeTray() { trayMenu = new ContextMenuStrip(); @@ -172,15 +173,16 @@ namespace OutlookCaseHelper trayMenu.Items.Add("About", null, About_Click); trayMenu.Items.Add("Exit", null, Exit_Click); - trayIcon = new NotifyIcon(); - trayIcon.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); - trayIcon.ContextMenuStrip = trayMenu; - trayIcon.Text = "Outlook Case Manager"; - trayIcon.Visible = true; + trayIcon = new NotifyIcon + { + Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")), + ContextMenuStrip = trayMenu, + Text = "Outlook Case Manager", + Visible = true + }; trayIcon.MouseDoubleClick += TrayIcon_MouseDoubleClick; - using var regKey = Registry.CurrentUser.OpenSubKey( - @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false); + using var regKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false); foreach (ToolStripItem menuItem in trayMenu.Items) { if (menuItem is ToolStripMenuItem item && item.Text == "Start with Windows") @@ -191,17 +193,24 @@ namespace OutlookCaseHelper } } + private void TrayIcon_MouseDoubleClick(object? sender, MouseEventArgs e) + => ProcessEmail_Click(null, EventArgs.Empty); + + private void Exit_Click(object? sender, EventArgs e) + { + monitorTimer.Stop(); + trayIcon.Visible = false; + Application.Exit(); + } + + // --- Tray Menu Handlers --- + private void ToggleStartup_Click(object? sender, EventArgs e) { - using var key = Registry.CurrentUser.OpenSubKey( - @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false); + using var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false); bool isEnabled = key?.GetValue("OutlookCaseHelper") != null; - SetStartupWithWindows(!isEnabled); - - if (sender is ToolStripMenuItem item) - item.Checked = !isEnabled; - + if (sender is ToolStripMenuItem item) item.Checked = !isEnabled; MessageBox.Show( !isEnabled ? "App will now start with Windows." : "App will no longer start with Windows.", "Settings", MessageBoxButtons.OK, MessageBoxIcon.Information); @@ -216,9 +225,7 @@ namespace OutlookCaseHelper return; } - _settingsForm = new HotkeySettingsForm( - hotkeyCreateMod, hotkeyCreateKey, - hotkeyRemoveMod, hotkeyRemoveKey); + _settingsForm = new HotkeySettingsForm(hotkeyCreateMod, hotkeyCreateKey, hotkeyRemoveMod, hotkeyRemoveKey); _settingsForm.Owner = this; _settingsForm.FormClosed += (s, args) => { @@ -254,20 +261,6 @@ namespace OutlookCaseHelper _dashboardForm.Show(); } - private void InitializeTimer() - { - monitorTimer = new System.Windows.Forms.Timer(); - monitorTimer.Interval = 60000; - monitorTimer.Tick += MonitorTimer_Tick; - monitorTimer.Start(); - } - - private void MonitorTimer_Tick(object? sender, EventArgs e) - { - try { outlookHelper.ProcessActiveRules(); } - catch { } - } - private void RunAllRules_Click(object? sender, EventArgs e) { try @@ -276,8 +269,7 @@ namespace OutlookCaseHelper Task.Run(() => { outlookHelper.RunAllRules(); - this.Invoke(() => - trayIcon.ShowBalloonTip(3000, "Outlook Case Manager", "All rules applied successfully!", ToolTipIcon.Info)); + this.Invoke(() => trayIcon.ShowBalloonTip(3000, "Outlook Case Manager", "All rules applied successfully!", ToolTipIcon.Info)); }); } catch (Exception ex) @@ -286,6 +278,10 @@ namespace OutlookCaseHelper } } + private void About_Click(object? sender, EventArgs e) => new AboutForm().ShowDialog(); + + // --- Rule Actions --- + private void ProcessEmail_Click(object? sender, EventArgs e) { try @@ -293,126 +289,91 @@ namespace OutlookCaseHelper var trackingId = outlookHelper.GetSelectedEmailTrackingId(); if (string.IsNullOrEmpty(trackingId)) { - MessageBox.Show( - "No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111", + MessageBox.Show("No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (outlookHelper.FindRuleByTrackingId(trackingId) != null) { - MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (outlookHelper.ExistsInClosed(trackingId)) { - var triggerEmail = outlookHelper.GetSelectedEmail(); - bool reopened = outlookHelper.ReopenFromClosed(trackingId, triggerEmail); - if (reopened) - MessageBox.Show( - $"Case reopened! Folder moved from Closed to Active.\n\nTrackingID: {trackingId}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error reopening case.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + HandleReopen(trackingId, outlookHelper.GetSelectedEmail()); return; } var ruleForm = new CreateRuleForm(trackingId, readonlyId: true); if (ruleForm.ShowDialog() != DialogResult.OK) return; - string folderName = ruleForm.FolderName; - bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName); - if (success) - MessageBox.Show( - $"Rule created! Emails moved and monitoring started.\n\nFolder: {folderName}\nActive rules: {outlookHelper.GetActiveRules().Count}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error processing email. Make sure Outlook is open.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (Exception ex) - { - MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + HandleCreate(trackingId, ruleForm.FolderName); } + catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void CreateRuleManual_Click(object? sender, EventArgs e) { + if (_createRuleForm != null && !_createRuleForm.IsDisposed) + { + _createRuleForm.BringToFront(); + _createRuleForm.WindowState = FormWindowState.Normal; + return; + } + try { - var ruleForm = new CreateRuleForm("", readonlyId: false); - if (ruleForm.ShowDialog() != DialogResult.OK) return; - - string trackingId = ruleForm.TrackingId; - string folderName = ruleForm.FolderName; - - if (outlookHelper.FindRuleByTrackingId(trackingId) != null) + _createRuleForm = new CreateRuleForm("", readonlyId: false); + _createRuleForm.FormClosed += (s, args) => { - MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } + if (_createRuleForm?.DialogResult == DialogResult.OK) + { + string trackingId = _createRuleForm.TrackingId; + string folderName = _createRuleForm.FolderName; - if (outlookHelper.ExistsInClosed(trackingId)) - { - bool reopened = outlookHelper.ReopenFromClosed(trackingId); - if (reopened) - MessageBox.Show( - $"Case reopened! Folder moved from Closed to Active.\n\nTrackingID: {trackingId}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error reopening case.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - return; - } - - bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName); - if (success) - MessageBox.Show( - $"Rule created! Emails moved and monitoring started.\n\nFolder: {folderName}\nActive rules: {outlookHelper.GetActiveRules().Count}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error creating rule. Make sure Outlook is open.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (Exception ex) - { - MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + if (outlookHelper.FindRuleByTrackingId(trackingId) != null) + { MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } + else if (outlookHelper.ExistsInClosed(trackingId)) + HandleReopen(trackingId); + else + HandleCreate(trackingId, folderName); + } + _createRuleForm = null; + }; + _createRuleForm.Show(); } + catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void RemoveRule_Click(object? sender, EventArgs e) { + if (_removeRuleForm != null && !_removeRuleForm.IsDisposed) + { + _removeRuleForm.BringToFront(); + _removeRuleForm.WindowState = FormWindowState.Normal; + return; + } + try { - var form = new InputForm("Enter TrackingID to remove:", "Remove Rule"); - if (form.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(form.Value)) + _removeRuleForm = new InputForm("Enter TrackingID to remove:", "Remove Rule"); + _removeRuleForm.FormClosed += (s, args) => { - string? folderName = outlookHelper.FindRuleByTrackingId(form.Value.Trim()); - if (folderName == null) + if (_removeRuleForm?.DialogResult == DialogResult.OK && !string.IsNullOrEmpty(_removeRuleForm.Value)) { - MessageBox.Show($"No active rule found for TrackingID#{form.Value}.", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; + string? folderName = outlookHelper.FindRuleByTrackingId(_removeRuleForm.Value.Trim()); + if (folderName == null) + MessageBox.Show($"No active rule found for TrackingID#{_removeRuleForm.Value}.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + else + HandleRemove(folderName); } - - bool success = outlookHelper.RemoveRuleAndMoveToClosed(folderName); - if (success) - MessageBox.Show( - $"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error removing rule. Check if folder exists.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - } - catch (Exception ex) - { - MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + _removeRuleForm = null; + }; + _removeRuleForm.Show(); } + catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void RemoveRuleFromSelected_Click(object? sender, EventArgs e) @@ -422,8 +383,7 @@ namespace OutlookCaseHelper var trackingId = outlookHelper.GetSelectedEmailTrackingId(); if (string.IsNullOrEmpty(trackingId)) { - MessageBox.Show( - "No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111", + MessageBox.Show("No email selected or ID not found in subject.\n\nExpected format: Title - TrackingID#1111111111111111", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } @@ -431,54 +391,59 @@ namespace OutlookCaseHelper string? folderName = outlookHelper.FindRuleByTrackingId(trackingId); if (folderName == null) { - MessageBox.Show($"No active rule found for TrackingID#{trackingId}.", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show($"No active rule found for TrackingID#{trackingId}.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } - bool success = outlookHelper.RemoveRuleAndMoveToClosed(folderName); - if (success) - MessageBox.Show( - $"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - else - MessageBox.Show("Error removing rule. Check if folder exists and Outlook is open.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - catch (Exception ex) - { - MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + HandleRemove(folderName); } + catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } - private void TrayIcon_MouseDoubleClick(object? sender, MouseEventArgs e) + // --- Shared Action Helpers --- + + private void HandleCreate(string trackingId, string folderName) { - ProcessEmail_Click(null, EventArgs.Empty); + if (outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName)) + MessageBox.Show($"Rule created! Emails moved and monitoring started.\n\nFolder: {folderName}\nActive rules: {outlookHelper.GetActiveRules().Count}", + "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show("Error creating rule. Make sure Outlook is open.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } - private void Exit_Click(object? sender, EventArgs e) + private void HandleReopen(string trackingId, Outlook.MailItem? triggerEmail = null) { - monitorTimer.Stop(); - trayIcon.Visible = false; - Application.Exit(); + if (outlookHelper.ReopenFromClosed(trackingId, triggerEmail)) + MessageBox.Show($"Case reopened! Folder moved from Closed to Active.\n\nTrackingID: {trackingId}", + "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show("Error reopening case.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } + private void HandleRemove(string folderName) + { + if (outlookHelper.RemoveRuleAndMoveToClosed(folderName)) + MessageBox.Show($"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.", + "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show("Error removing rule. Check if folder exists.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + // --- Inner Forms --- + private class DashboardForm : Form { - private ListView listView = null!; - private OutlookHelper outlookHelper; + private readonly ListView listView; + private readonly OutlookHelper outlookHelper; public DashboardForm(OutlookHelper helper) { outlookHelper = helper; - this.Text = "Active Rules"; this.Size = new Size(720, 450); - this.MinimumSize = new Size(720, 450); - this.MaximumSize = new Size(720, 450); + this.MinimumSize = this.MaximumSize = this.Size; this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; + this.MaximizeBox = this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; try { this.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); } catch { } @@ -512,12 +477,7 @@ namespace OutlookCaseHelper btnRefresh.Click += (s, e) => LoadRules(); btnDismiss.Click += (s, e) => this.Close(); - this.Controls.AddRange(new Control[] - { - listView, - btnAdd, btnRename, btnClose, btnReload, btnRefresh, btnDismiss - }); - + this.Controls.AddRange(new Control[] { listView, btnAdd, btnRename, btnClose, btnReload, btnRefresh, btnDismiss }); LoadRules(); } @@ -529,8 +489,7 @@ namespace OutlookCaseHelper if (rules.Count == 0) { var empty = new ListViewItem("No active rules found."); - empty.SubItems.Add(""); - empty.SubItems.Add(""); + empty.SubItems.Add(""); empty.SubItems.Add(""); listView.Items.Add(empty); return; } @@ -555,46 +514,29 @@ namespace OutlookCaseHelper if (outlookHelper.FindRuleByTrackingId(trackingId) != null) { - MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", - "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } if (outlookHelper.ExistsInClosed(trackingId)) { - bool reopened = outlookHelper.ReopenFromClosed(trackingId); - if (reopened) - { - MessageBox.Show($"Case reopened!\n\nTrackingID: {trackingId}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - LoadRules(); - } + if (outlookHelper.ReopenFromClosed(trackingId)) + { MessageBox.Show($"Case reopened!\n\nTrackingID: {trackingId}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); } else - MessageBox.Show("Error reopening case.", "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Error reopening case.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName); - if (success) - { - MessageBox.Show($"Rule created!\n\nFolder: {folderName}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - LoadRules(); - } + if (outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName)) + { MessageBox.Show($"Rule created!\n\nFolder: {folderName}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); } else - MessageBox.Show("Error creating rule. Make sure Outlook is open.", - "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Error creating rule. Make sure Outlook is open.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } private void BtnRename_Click(object? sender, EventArgs e) { if (listView.SelectedItems.Count == 0) - { - MessageBox.Show("Please select a rule to rename.", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } + { MessageBox.Show("Please select a rule to rename.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var rule = listView.SelectedItems[0].Tag as OutlookHelper.RuleInfo; if (rule == null) return; @@ -616,75 +558,49 @@ namespace OutlookCaseHelper var txt = new TextBox { Left = 20, Top = 40, Width = 370, Height = 24, Text = rule.FolderName }; var btnOk = new Button { Text = "Rename", Left = 210, Top = 80, Width = 80, DialogResult = DialogResult.OK }; var btnCancel = new Button { Text = "Cancel", Left = 300, Top = 80, Width = 80, DialogResult = DialogResult.Cancel }; - inputForm.Controls.AddRange(new Control[] { lbl, txt, btnOk, btnCancel }); - inputForm.AcceptButton = btnOk; - inputForm.CancelButton = btnCancel; + inputForm.AcceptButton = btnOk; inputForm.CancelButton = btnCancel; if (inputForm.ShowDialog() != DialogResult.OK) return; - string newName = txt.Text.Trim(); if (string.IsNullOrEmpty(newName) || newName == rule.FolderName) return; - bool success = outlookHelper.RenameRule(rule.FolderName, newName); - if (success) - { - MessageBox.Show($"Rule renamed!\n\n{rule.FolderName} → {newName}", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - LoadRules(); - } + if (outlookHelper.RenameRule(rule.FolderName, newName)) + { MessageBox.Show($"Rule renamed!\n\n{rule.FolderName} → {newName}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); } else - MessageBox.Show("Error renaming rule.", "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Error renaming rule.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } private void BtnClose_Click(object? sender, EventArgs e) { if (listView.SelectedItems.Count == 0) - { - MessageBox.Show("Please select a rule to close.", "Warning", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - return; - } + { MessageBox.Show("Please select a rule to close.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var rule = listView.SelectedItems[0].Tag as OutlookHelper.RuleInfo; if (rule == null) return; - var confirm = MessageBox.Show( + if (MessageBox.Show( $"Are you sure you want to close this case?\n\nFolder: {rule.FolderName}\n\nThe folder will be moved to Inbox > Cases > Closed.", - "Close Case", MessageBoxButtons.YesNo, MessageBoxIcon.Question); + "Close Case", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return; - if (confirm != DialogResult.Yes) return; - - bool success = outlookHelper.RemoveRuleAndMoveToClosed(rule.FolderName); - if (success) - { - MessageBox.Show("Case closed!\n\nFolder moved to: Inbox > Cases > Closed.", - "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); - LoadRules(); - } + if (outlookHelper.RemoveRuleAndMoveToClosed(rule.FolderName)) + { MessageBox.Show("Case closed!\n\nFolder moved to: Inbox > Cases > Closed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); } else - MessageBox.Show("Error closing case.", "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Error closing case.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } private void BtnReload_Click(object? sender, EventArgs e) { if (this.Owner is Form1 form1) - { - form1.ReloadOutlookRules(); - LoadRules(); - MessageBox.Show("Rules reloaded successfully!", "Success", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } + { form1.ReloadOutlookRules(); LoadRules(); MessageBox.Show("Rules reloaded successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } private class HotkeySettingsForm : Form { - private CheckBox chkCreateAlt, chkCreateCtrl, chkCreateShift; - private CheckBox chkRemoveAlt, chkRemoveCtrl, chkRemoveShift; - private ComboBox cmbCreateKey, cmbRemoveKey; + private readonly CheckBox chkCreateAlt, chkCreateCtrl, chkCreateShift; + private readonly CheckBox chkRemoveAlt, chkRemoveCtrl, chkRemoveShift; + private readonly ComboBox cmbCreateKey, cmbRemoveKey; public uint CreateMod { get; private set; } public uint CreateKey { get; private set; } @@ -704,11 +620,9 @@ namespace OutlookCaseHelper { this.Text = "Hotkey Settings"; this.Size = new Size(420, 280); - this.MinimumSize = new Size(420, 280); - this.MaximumSize = new Size(420, 280); + this.MinimumSize = this.MaximumSize = this.Size; this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; + this.MaximizeBox = this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; try { this.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); } catch { } @@ -734,14 +648,9 @@ namespace OutlookCaseHelper { try { - string rulesPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "OutlookCaseHelper", "active_rules.json"); - if (File.Exists(rulesPath)) - System.Diagnostics.Process.Start("notepad.exe", rulesPath); - else - MessageBox.Show("No rules file found.", "Info", - MessageBoxButtons.OK, MessageBoxIcon.Information); + string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "OutlookCaseHelper", "active_rules.json"); + if (File.Exists(path)) System.Diagnostics.Process.Start("notepad.exe", path); + else MessageBox.Show("No rules file found.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch { } }; @@ -752,11 +661,7 @@ namespace OutlookCaseHelper try { if (this.Owner is Form1 form1) - { - form1.ReloadOutlookRules(); - MessageBox.Show("Rules reloaded successfully!", "Success", - MessageBoxButtons.OK, MessageBoxIcon.Information); - } + { form1.ReloadOutlookRules(); MessageBox.Show("Rules reloaded successfully!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); } } catch { } }; @@ -769,7 +674,6 @@ namespace OutlookCaseHelper lblRemove, chkRemoveAlt, chkRemoveCtrl, chkRemoveShift, cmbRemoveKey, btnViewRules, btnReloadRules, btnOk, btnCancel }); - this.AcceptButton = btnOk; this.CancelButton = btnCancel; } @@ -777,23 +681,16 @@ namespace OutlookCaseHelper private void SelectKey(ComboBox cmb, uint keyCode) { var key = (Keys)keyCode; - string keyName = key.ToString(); - if (keyName.StartsWith("F") && int.TryParse(keyName.Substring(1), out _)) - cmb.SelectedItem = keyName; - else if (keyName.StartsWith("D") && keyName.Length == 2) - cmb.SelectedItem = keyName.Substring(1); - else - cmb.SelectedItem = keyName; - + string name = key.ToString(); + cmb.SelectedItem = name.StartsWith("F") && int.TryParse(name[1..], out _) ? name + : name.StartsWith("D") && name.Length == 2 ? name[1..] : name; if (cmb.SelectedIndex < 0) cmb.SelectedIndex = 0; } private uint GetKeyCode(ComboBox cmb) { - string selected = cmb.SelectedItem?.ToString() ?? "F1"; - if (int.TryParse(selected, out _)) - return (uint)(Keys)Enum.Parse(typeof(Keys), "D" + selected); - return (uint)(Keys)Enum.Parse(typeof(Keys), selected); + string s = cmb.SelectedItem?.ToString() ?? "F1"; + return (uint)(Keys)Enum.Parse(typeof(Keys), int.TryParse(s, out _) ? "D" + s : s); } private uint GetMod(CheckBox alt, CheckBox ctrl, CheckBox shift) @@ -819,21 +716,15 @@ namespace OutlookCaseHelper { if (this.DialogResult == DialogResult.OK) { - uint createMod = GetMod(chkCreateAlt, chkCreateCtrl, chkCreateShift); - uint removeMod = GetMod(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift); - - if (createMod == 0 || removeMod == 0) + uint cm = GetMod(chkCreateAlt, chkCreateCtrl, chkCreateShift); + uint rm = GetMod(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift); + if (cm == 0 || rm == 0) { - MessageBox.Show("Please select at least one modifier (Alt, Ctrl or Shift) for each shortcut.", - "Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning); - e.Cancel = true; - return; + MessageBox.Show("Please select at least one modifier (Alt, Ctrl or Shift) for each shortcut.", "Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning); + e.Cancel = true; return; } - - CreateMod = createMod; - CreateKey = GetKeyCode(cmbCreateKey); - RemoveMod = removeMod; - RemoveKey = GetKeyCode(cmbRemoveKey); + CreateMod = cm; CreateKey = GetKeyCode(cmbCreateKey); + RemoveMod = rm; RemoveKey = GetKeyCode(cmbRemoveKey); CreateDescription = GetDescription(chkCreateAlt, chkCreateCtrl, chkCreateShift, cmbCreateKey); RemoveDescription = GetDescription(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift, cmbRemoveKey); } @@ -843,9 +734,8 @@ namespace OutlookCaseHelper private class CreateRuleForm : Form { - private TextBox txtId; - private TextBox txtName; - private Label lblPreview; + private readonly TextBox txtId, txtName; + private readonly Label lblPreview; public string TrackingId { get; private set; } = ""; public string FolderName { get; private set; } = ""; @@ -853,22 +743,20 @@ namespace OutlookCaseHelper { this.Text = "Create Rule"; this.Size = new Size(420, 230); - this.MinimumSize = new Size(420, 230); - this.MaximumSize = new Size(420, 230); + this.MinimumSize = this.MaximumSize = this.Size; this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; + this.MaximizeBox = this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; try { this.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); } catch { } var lblId = new Label { Text = "TrackingID (required):", Left = 20, Top = 15, Width = 370, Height = 20 }; txtId = new TextBox { Left = 20, Top = 38, Width = 370, Height = 24, Text = trackingId, ReadOnly = readonlyId }; - if (readonlyId) txtId.BackColor = System.Drawing.SystemColors.Control; + if (readonlyId) txtId.BackColor = SystemColors.Control; var lblName = new Label { Text = "Additional name (optional):", Left = 20, Top = 72, Width = 370, Height = 20 }; txtName = new TextBox { Left = 20, Top = 95, Width = 370, Height = 24 }; - lblPreview = new Label { Left = 20, Top = 128, Width = 370, Height = 20, ForeColor = System.Drawing.Color.Gray }; + lblPreview = new Label { Left = 20, Top = 128, Width = 370, Height = 20, ForeColor = Color.Gray }; UpdatePreview(trackingId); var btnOk = new Button { Text = "OK", Left = 220, Top = 158, Width = 80, DialogResult = DialogResult.OK }; @@ -885,9 +773,7 @@ namespace OutlookCaseHelper private void UpdatePreview(string id) { string name = txtName?.Text.Trim() ?? ""; - string preview = string.IsNullOrEmpty(name) ? id : $"{id} | {name}"; - if (lblPreview != null) - lblPreview.Text = $"Folder: {preview}"; + lblPreview.Text = $"Folder: {(string.IsNullOrEmpty(name) ? id : $"{id} | {name}")}"; } protected override void OnFormClosing(FormClosingEventArgs e) @@ -895,16 +781,12 @@ namespace OutlookCaseHelper if (this.DialogResult == DialogResult.OK) { TrackingId = txtId.Text.Trim(); - string name = txtName.Text.Trim(); - if (string.IsNullOrEmpty(TrackingId)) { - MessageBox.Show("TrackingID is required!", "Validation", - MessageBoxButtons.OK, MessageBoxIcon.Warning); - e.Cancel = true; - return; + MessageBox.Show("TrackingID is required!", "Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning); + e.Cancel = true; return; } - + string name = txtName.Text.Trim(); FolderName = string.IsNullOrEmpty(name) ? TrackingId : $"{TrackingId} | {name}"; } base.OnFormClosing(e); @@ -913,24 +795,21 @@ namespace OutlookCaseHelper private class InputForm : Form { - private TextBox txtInput; + private readonly TextBox txtInput; public string Value { get; private set; } = ""; public InputForm(string prompt, string title) { this.Text = title; this.Size = new Size(380, 150); - this.MinimumSize = new Size(380, 150); - this.MaximumSize = new Size(380, 150); + this.MinimumSize = this.MaximumSize = this.Size; this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; + this.MaximizeBox = this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; try { this.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); } catch { } var label = new Label { Text = prompt, Left = 20, Top = 15, Width = 330, Height = 25 }; txtInput = new TextBox { Left = 20, Top = 45, Width = 330, Height = 24 }; - var btnOk = new Button { Text = "OK", Left = 155, Top = 80, Width = 80, DialogResult = DialogResult.OK }; var btnCancel = new Button { Text = "Cancel", Left = 245, Top = 80, Width = 80, DialogResult = DialogResult.Cancel }; @@ -942,14 +821,11 @@ namespace OutlookCaseHelper protected override void OnFormClosing(FormClosingEventArgs e) { Value = txtInput.Text; + if (this.DialogResult == DialogResult.None) + this.DialogResult = DialogResult.Cancel; base.OnFormClosing(e); } } - private void About_Click(object? sender, EventArgs e) - { - var form = new AboutForm(); - form.ShowDialog(); - } private class AboutForm : Form { @@ -957,150 +833,32 @@ namespace OutlookCaseHelper { this.Text = "About Outlook Case Manager"; this.Size = new Size(400, 340); - this.MinimumSize = new Size(400, 340); - this.MaximumSize = new Size(400, 340); + this.MinimumSize = this.MaximumSize = this.Size; this.FormBorderStyle = FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; + this.MaximizeBox = this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; try { this.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")); } catch { } - // Ícone grande - var pictureBox = new PictureBox - { - Left = 160, - Top = 20, - Width = 64, - Height = 64, - SizeMode = PictureBoxSizeMode.StretchImage - }; + var pictureBox = new PictureBox { Left = 160, Top = 20, Width = 64, Height = 64, SizeMode = PictureBoxSizeMode.StretchImage }; try { pictureBox.Image = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "casenew.ico")).ToBitmap(); } catch { } - // Nome da app - var lblName = new Label - { - Text = "Outlook Case Manager", - Left = 20, - Top = 95, - Width = 350, - Height = 28, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 14, FontStyle.Bold) - }; + var lblName = new Label { Text = "Outlook Case Manager", Left = 20, Top = 95, Width = 350, Height = 28, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 14, FontStyle.Bold) }; + var lblVersion = new Label { Text = "Version 1.0.0", Left = 20, Top = 125, Width = 350, Height = 22, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 10), ForeColor = Color.Gray }; + var lblDate = new Label { Text = "Released: March 2026", Left = 20, Top = 148, Width = 350, Height = 20, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 9), ForeColor = Color.Gray }; + var lblDesc = new Label { Text = "Automatically organizes Outlook emails by TrackingID\ninto folders, keeping your inbox clean and cases managed.", Left = 30, Top = 178, Width = 330, Height = 40, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 9) }; + var separator = new Label { Left = 20, Top = 228, Width = 350, Height = 1, BorderStyle = BorderStyle.Fixed3D }; + var lblCreatedBy = new Label { Text = "Created by Wellington Ribeiro", Left = 20, Top = 238, Width = 350, Height = 18, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 9, FontStyle.Bold) }; - // Versão - var lblVersion = new Label - { - Text = "Version 1.0.0", - Left = 20, - Top = 125, - Width = 350, - Height = 22, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 10, FontStyle.Regular), - ForeColor = Color.Gray - }; - - // Data de lançamento - var lblDate = new Label - { - Text = "Released: March 2026", - Left = 20, - Top = 148, - Width = 350, - Height = 20, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 9, FontStyle.Regular), - ForeColor = Color.Gray - }; - - // Descrição - var lblDesc = new Label - { - Text = "Automatically organizes Outlook emails by TrackingID\ninto folders, keeping your inbox clean and cases managed.", - Left = 30, - Top = 178, - Width = 330, - Height = 40, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 9, FontStyle.Regular) - }; - - // Separador - var separator = new Label - { - Left = 20, - Top = 228, - Width = 350, - Height = 1, - BorderStyle = BorderStyle.Fixed3D - }; - - // Created by - var lblCreatedBy = new Label - { - Text = "Created by Wellington Ribeiro", - Left = 20, - Top = 238, - Width = 350, - Height = 18, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 9, FontStyle.Bold) - }; - - // Email — clicável - var lblEmail = new LinkLabel - { - Text = "wribeiro@microsoft.com", - Left = 20, - Top = 258, - Width = 350, - Height = 18, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 9, FontStyle.Regular) - }; + var lblEmail = new LinkLabel { Text = "wribeiro@microsoft.com", Left = 20, Top = 258, Width = 350, Height = 18, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 9) }; lblEmail.LinkClicked += (s, e) => { - try - { - System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo - { - FileName = "mailto:wribeiro@microsoft.com?subject=Outlook Case Manager - Feedback", - UseShellExecute = true - }); - } - catch { } + try { System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = "mailto:wribeiro@microsoft.com?subject=Outlook Case Manager - Feedback", UseShellExecute = true }); } catch { } }; - // Sugestões - var lblSuggestions = new Label - { - Text = "For suggestions or bugs, contact the email above.", - Left = 20, - Top = 278, - Width = 350, - Height = 18, - TextAlign = ContentAlignment.MiddleCenter, - Font = new Font("Segoe UI", 8, FontStyle.Italic), - ForeColor = Color.Gray - }; - - // Botão fechar - var btnClose = new Button - { - Text = "Close", - Left = 150, - Top = 302, - Width = 90, - DialogResult = DialogResult.Cancel - }; - - this.Controls.AddRange(new Control[] - { - pictureBox, lblName, lblVersion, lblDate, lblDesc, - separator, lblCreatedBy, lblEmail, lblSuggestions, btnClose - }); + var lblSuggestions = new Label { Text = "For suggestions or bugs, contact the email above.", Left = 20, Top = 278, Width = 350, Height = 18, TextAlign = ContentAlignment.MiddleCenter, Font = new Font("Segoe UI", 8, FontStyle.Italic), ForeColor = Color.Gray }; + var btnClose = new Button { Text = "Close", Left = 150, Top = 302, Width = 90, DialogResult = DialogResult.Cancel }; + this.Controls.AddRange(new Control[] { pictureBox, lblName, lblVersion, lblDate, lblDesc, separator, lblCreatedBy, lblEmail, lblSuggestions, btnClose }); this.CancelButton = btnClose; } } diff --git a/OutlookCaseHelper/OutlookHelper.cs b/OutlookCaseHelper/OutlookHelper.cs index 12ed24b..95fc6e4 100644 --- a/OutlookCaseHelper/OutlookHelper.cs +++ b/OutlookCaseHelper/OutlookHelper.cs @@ -4,7 +4,6 @@ using System.Text.RegularExpressions; using System.IO; using System.Text.Json; using System.Windows.Forms; -using System.Threading.Tasks; using Outlook = Microsoft.Office.Interop.Outlook; namespace OutlookCaseHelper @@ -13,11 +12,18 @@ namespace OutlookCaseHelper { private Outlook.Application? outlookApp; private Outlook.NameSpace? outlookNamespace; - private HashSet activeRules = new HashSet(); + private HashSet activeRules = new(); private readonly string rulesFilePath; private Outlook.Items? inboxItems; private Outlook.Items? sentItems; + public class RuleInfo + { + public string FolderName { get; set; } = ""; + public string TrackingId { get; set; } = ""; + public int EmailCount { get; set; } + } + public OutlookHelper() { rulesFilePath = Path.Combine( @@ -28,14 +34,16 @@ namespace OutlookCaseHelper LoadRules(); } + // --- Outlook Connection --- + private bool EnsureOutlookConnected() { if (outlookApp != null && outlookNamespace != null) return true; try { - var outlookProcess = System.Diagnostics.Process.GetProcessesByName("OUTLOOK"); - if (outlookProcess.Length == 0) return false; + if (System.Diagnostics.Process.GetProcessesByName("OUTLOOK").Length == 0) + return false; outlookApp = new Outlook.Application(); outlookNamespace = outlookApp.GetNamespace("MAPI"); @@ -50,26 +58,29 @@ namespace OutlookCaseHelper { try { - Outlook.Folder? inboxFolder = - outlookNamespace?.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - Outlook.Folder? sentFolder = - outlookNamespace?.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder; + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail); - if (inboxFolder != null) + if (inbox != null) { - inboxItems = inboxFolder.Items; + inboxItems = inbox.Items; inboxItems.ItemAdd += OnEmailReceived; } - if (sentFolder != null) + if (sent != null) { - sentItems = sentFolder.Items; + sentItems = sent.Items; sentItems.ItemAdd += OnEmailSent; } } catch { } } - private void OnEmailReceived(object item) + // --- Email Events --- + + private void OnEmailReceived(object item) => MoveEmailIfRuleExists(item); + private void OnEmailSent(object item) => MoveEmailIfRuleExists(item); + + private void MoveEmailIfRuleExists(object item) { try { @@ -81,214 +92,88 @@ namespace OutlookCaseHelper foreach (var folderName in activeRules) { string trackingId = ExtractTrackingId(folderName); - if (mail.Subject.Contains($"TrackingID#{trackingId}")) - { - Outlook.Folder? inboxFolder = - outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return; + if (!mail.Subject.Contains($"TrackingID#{trackingId}")) continue; - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); - Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName); + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return; - mail.Move(trackingFolder); - break; - } + var target = GetOrCreateFolder(GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active"), folderName); + mail.Move(target); + break; } } catch { } } - private void OnEmailSent(object item) - { - try - { - if (outlookNamespace == null) return; - if (activeRules.Count == 0) return; - if (item is not Outlook.MailItem mail) return; - if (mail.Subject == null) return; + // --- Rules Management --- - foreach (var folderName in activeRules) - { - string trackingId = ExtractTrackingId(folderName); - if (mail.Subject.Contains($"TrackingID#{trackingId}")) - { - Outlook.Folder? inboxFolder = - outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return; - - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); - Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName); - - mail.Move(trackingFolder); - break; - } - } - } - catch { } - } - - private string ExtractTrackingId(string folderName) - { - var match = Regex.Match(folderName, @"^(\d+)"); - return match.Success ? match.Groups[1].Value : folderName; - } + public HashSet GetActiveRules() => activeRules; public string? FindRuleByTrackingId(string trackingId) { foreach (var rule in activeRules) - { - if (ExtractTrackingId(rule) == trackingId) - return rule; - } + if (ExtractTrackingId(rule) == trackingId) return rule; return null; } - public bool ExistsInClosed(string trackingId) - { - try - { - if (!EnsureOutlookConnected()) return false; - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return false; - - Outlook.Folder? casesFolder = GetFolder(inboxFolder, "Cases"); - if (casesFolder == null) return false; - - Outlook.Folder? closedFolder = GetFolder(casesFolder, "Closed"); - if (closedFolder == null) return false; - - return GetFolderStartingWith(closedFolder, trackingId) != null; - } - catch { return false; } - } - - private void LoadRules() - { - try - { - if (File.Exists(rulesFilePath)) - { - var json = File.ReadAllText(rulesFilePath); - var rules = JsonSerializer.Deserialize>(json); - if (rules != null) - activeRules = new HashSet(rules); - } - } - catch { } - } - - private void SaveRules() - { - try - { - var json = JsonSerializer.Serialize(new List(activeRules)); - File.WriteAllText(rulesFilePath, json); - } - catch { } - } - public void ReloadRules() { activeRules.Clear(); LoadRules(); } - public HashSet GetActiveRules() => activeRules; + public void ProcessActiveRules() { } + + private void LoadRules() + { + try + { + if (!File.Exists(rulesFilePath)) return; + var rules = JsonSerializer.Deserialize>(File.ReadAllText(rulesFilePath)); + if (rules != null) activeRules = new HashSet(rules); + } + catch { } + } + + private void SaveRules() + { + try { File.WriteAllText(rulesFilePath, JsonSerializer.Serialize(new List(activeRules))); } + catch { } + } + + // --- Outlook Operations --- public string? GetSelectedEmailTrackingId() { if (!EnsureOutlookConnected()) return null; try { - Outlook.Explorer activeExplorer = outlookApp!.ActiveExplorer(); - if (activeExplorer == null) return null; - - Outlook.Selection selection = activeExplorer.Selection; - if (selection.Count == 0) return null; - - Outlook.MailItem? email = selection[1] as Outlook.MailItem; + var email = outlookApp!.ActiveExplorer()?.Selection?[1] as Outlook.MailItem; if (email == null) return null; - - Match match = Regex.Match(email.Subject, @"TrackingID#(\d+)"); - if (match.Success) - return match.Groups[1].Value; - - return null; + var match = Regex.Match(email.Subject, @"TrackingID#(\d+)"); + return match.Success ? match.Groups[1].Value : null; } catch { return null; } } - public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null) + public Outlook.MailItem? GetSelectedEmail() + { + if (!EnsureOutlookConnected()) return null; + try { return outlookApp!.ActiveExplorer()?.Selection?[1] as Outlook.MailItem; } + catch { return null; } + } + + public bool ExistsInClosed(string trackingId) { - if (!EnsureOutlookConnected()) return false; try { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return false; - - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); - Outlook.Folder? closedFolder = GetFolder(casesFolder, "Closed"); - if (closedFolder == null) return false; - - Outlook.Folder? closedTracking = GetFolderStartingWith(closedFolder, trackingId); - if (closedTracking == null) return false; - - string existingName = closedTracking.Name; - - Outlook.Folder? existingActive = GetFolder(activeFolder, existingName); - if (existingActive != null) - { - var toMove = new List(); - foreach (object item in closedTracking.Items) - if (item is Outlook.MailItem mail) toMove.Add(mail); - foreach (var mail in toMove) - mail.Move(existingActive); - try { closedTracking.Delete(); } catch { } - } - else - { - closedTracking.MoveTo(activeFolder); - } - - if (triggerEmail != null) - { - try - { - Outlook.Folder? targetFolder = GetFolder(activeFolder, existingName); - if (targetFolder != null) - triggerEmail.Move(targetFolder); - } - catch { } - } - - activeRules.Add(existingName); - SaveRules(); - return true; - } - catch - { - try - { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - Outlook.Folder? casesFolder = GetFolder(inboxFolder!, "Cases"); - Outlook.Folder? activeFolder = GetFolder(casesFolder!, "Active"); - Outlook.Folder? movedFolder = GetFolderStartingWith(activeFolder!, trackingId); - if (movedFolder != null) - { - activeRules.Add(movedFolder.Name); - SaveRules(); - return true; - } - } - catch { } - return false; + if (!EnsureOutlookConnected()) return false; + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return false; + var closed = GetFolder(GetFolder(inbox, "Cases"), "Closed"); + return closed != null && GetFolderStartingWith(closed, trackingId) != null; } + catch { return false; } } public bool CreateFolderAndMoveEmails(string trackingId, string folderName) @@ -296,31 +181,23 @@ namespace OutlookCaseHelper if (!EnsureOutlookConnected()) return false; try { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return false; - - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); - Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName); + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return false; + var target = GetOrCreateFolder(GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active"), folderName); string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'"; - MoveFilteredEmails(inboxFolder, filter, trackingFolder); + MoveFilteredEmails(inbox, filter, target); - Outlook.Folder? sentFolder = - outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder; - if (sentFolder != null) - MoveFilteredEmails(sentFolder, filter, trackingFolder); + var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail); + if (sent != null) MoveFilteredEmails(sent, filter, target); - foreach (Outlook.Folder folder in inboxFolder.Parent.Folders) + foreach (Outlook.Folder folder in inbox.Parent.Folders) { if (folder.Name != "Cases" && - folder.EntryID != inboxFolder.EntryID && - folder.EntryID != sentFolder?.EntryID) - { - try { MoveFilteredEmails(folder, filter, trackingFolder); } catch { } - } + folder.EntryID != inbox.EntryID && + folder.EntryID != sent?.EntryID) + try { MoveFilteredEmails(folder, filter, target); } catch { } } activeRules.Add(folderName); @@ -334,41 +211,20 @@ namespace OutlookCaseHelper } } - private void MoveFilteredEmails(Outlook.Folder source, string filter, Outlook.Folder dest) - { - try - { - Outlook.Items restricted = source.Items.Restrict(filter); - var toMove = new List(); - foreach (object item in restricted) - if (item is Outlook.MailItem mail) toMove.Add(mail); - foreach (var mail in toMove) - mail.Move(dest); - } - catch { } - } - public bool RemoveRuleAndMoveToClosed(string folderName) { if (!EnsureOutlookConnected()) return false; try { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return false; + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return false; - Outlook.Folder? casesFolder = GetFolder(inboxFolder, "Cases"); - if (casesFolder == null) return false; - - Outlook.Folder? activeFolder = GetFolder(casesFolder, "Active"); - if (activeFolder == null) return false; - - Outlook.Folder? trackingFolder = GetFolder(activeFolder, folderName); - if (trackingFolder == null) return false; - - Outlook.Folder closedFolder = GetOrCreateFolder(casesFolder, "Closed"); - trackingFolder.MoveTo(closedFolder); + var cases = GetFolder(inbox, "Cases"); + var active = GetFolder(cases, "Active"); + var folder = GetFolder(active, folderName); + if (folder == null) return false; + folder.MoveTo(GetOrCreateFolder(cases!, "Closed")); activeRules.Remove(folderName); SaveRules(); return true; @@ -381,17 +237,9 @@ namespace OutlookCaseHelper if (!EnsureOutlookConnected()) return false; try { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return false; - - Outlook.Folder? casesFolder = GetFolder(inboxFolder, "Cases"); - if (casesFolder == null) return false; - - Outlook.Folder? activeFolder = GetFolder(casesFolder, "Active"); - if (activeFolder == null) return false; - - Outlook.Folder? folder = GetFolder(activeFolder, oldFolderName); + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + var active = GetFolder(GetFolder(inbox, "Cases"), "Active"); + var folder = GetFolder(active, oldFolderName); if (folder == null) return false; folder.Name = newFolderName; @@ -403,40 +251,163 @@ namespace OutlookCaseHelper catch { return false; } } - public void RunAllRules() + public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null) { - if (!EnsureOutlookConnected()) return; - if (activeRules.Count == 0) return; - + if (!EnsureOutlookConnected()) return false; try { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return; + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return false; - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); + var cases = GetOrCreateFolder(inbox, "Cases"); + var active = GetOrCreateFolder(cases, "Active"); + var closed = GetFolder(cases, "Closed"); + if (closed == null) return false; - var rootFolder = inboxFolder.Parent as Outlook.Folder; - var allFolders = new List(); - if (rootFolder != null) - GetAllFolders(rootFolder, allFolders, casesFolder.EntryID); + var closedTracking = GetFolderStartingWith(closed, trackingId); + if (closedTracking == null) return false; + + string existingName = closedTracking.Name; + var existingActive = GetFolder(active, existingName); + + if (existingActive != null) + { + var toMove = new List(); + foreach (object item in closedTracking.Items) + if (item is Outlook.MailItem m) toMove.Add(m); + foreach (var m in toMove) m.Move(existingActive); + try { closedTracking.Delete(); } catch { } + } + else + { + closedTracking.MoveTo(active); + } + + try + { + var target = GetFolder(active, existingName); + if (triggerEmail != null && target != null) + triggerEmail.Move(target); + } + catch { } + + activeRules.Add(existingName); + SaveRules(); + return true; + } + catch + { + try + { + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + var active = GetFolder(GetFolder(inbox, "Cases"), "Active"); + var moved = GetFolderStartingWith(active!, trackingId); + if (moved != null) { activeRules.Add(moved.Name); SaveRules(); return true; } + } + catch { } + return false; + } + } + + // --- Scan & Run Rules --- + + public void ScanInboxOnStartup() + { + if (activeRules.Count == 0 || !EnsureOutlookConnected()) return; + try + { + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail); + if (inbox == null) return; + + var active = GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active"); foreach (var folderName in activeRules) { string trackingId = ExtractTrackingId(folderName); string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'"; - Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName); + var target = GetOrCreateFolder(active, folderName); + + MoveFilteredEmails(inbox, filter, target); + if (sent != null) MoveFilteredEmails(sent, filter, target); + } + } + catch { } + } + + public void RunAllRules() + { + if (activeRules.Count == 0 || !EnsureOutlookConnected()) return; + try + { + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + if (inbox == null) return; + + var cases = GetOrCreateFolder(inbox, "Cases"); + var active = GetOrCreateFolder(cases, "Active"); + + var allFolders = new List(); + if (inbox.Parent is Outlook.Folder root) + GetAllFolders(root, allFolders, cases.EntryID); + + foreach (var folderName in activeRules) + { + string trackingId = ExtractTrackingId(folderName); + string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'"; + var target = GetOrCreateFolder(active, folderName); foreach (var folder in allFolders) - { - try { MoveFilteredEmails(folder, filter, trackingFolder); } catch { } - } + try { MoveFilteredEmails(folder, filter, target); } catch { } } } catch { } } + public List GetActiveRulesInfo() + { + var result = new List(); + if (!EnsureOutlookConnected()) return result; + try + { + var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); + var active = GetFolder(GetFolder(inbox, "Cases"), "Active"); + if (active == null) return result; + + foreach (var folderName in activeRules) + { + var folder = GetFolder(active, folderName); + result.Add(new RuleInfo + { + FolderName = folderName, + TrackingId = ExtractTrackingId(folderName), + EmailCount = folder?.Items.Count ?? 0 + }); + } + } + catch { } + return result; + } + + // --- Helpers --- + + private string ExtractTrackingId(string folderName) + { + var match = Regex.Match(folderName, @"^(\d+)"); + return match.Success ? match.Groups[1].Value : folderName; + } + + private void MoveFilteredEmails(Outlook.Folder source, string filter, Outlook.Folder dest) + { + try + { + var toMove = new List(); + foreach (object item in source.Items.Restrict(filter)) + if (item is Outlook.MailItem mail) toMove.Add(mail); + foreach (var mail in toMove) mail.Move(dest); + } + catch { } + } + private void GetAllFolders(Outlook.Folder parent, List result, string excludeEntryId) { foreach (Outlook.Folder folder in parent.Folders) @@ -452,118 +423,30 @@ namespace OutlookCaseHelper } } - public void ScanInboxOnStartup() - { - if (activeRules.Count == 0) return; - if (!EnsureOutlookConnected()) return; - - try - { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return; - - Outlook.Folder? sentFolder = - outlookNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder; - - Outlook.Folder casesFolder = GetOrCreateFolder(inboxFolder, "Cases"); - Outlook.Folder activeFolder = GetOrCreateFolder(casesFolder, "Active"); - - foreach (var folderName in activeRules) - { - string trackingId = ExtractTrackingId(folderName); - string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'"; - Outlook.Folder trackingFolder = GetOrCreateFolder(activeFolder, folderName); - - MoveFilteredEmails(inboxFolder, filter, trackingFolder); - if (sentFolder != null) - MoveFilteredEmails(sentFolder, filter, trackingFolder); - } - } - catch { } - } - - public class RuleInfo - { - public string FolderName { get; set; } = ""; - public string TrackingId { get; set; } = ""; - public int EmailCount { get; set; } - } - - public List GetActiveRulesInfo() - { - var result = new List(); - if (!EnsureOutlookConnected()) return result; - - try - { - Outlook.Folder? inboxFolder = - outlookNamespace!.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder; - if (inboxFolder == null) return result; - - Outlook.Folder? casesFolder = GetFolder(inboxFolder, "Cases"); - if (casesFolder == null) return result; - - Outlook.Folder? activeFolder = GetFolder(casesFolder, "Active"); - if (activeFolder == null) return result; - - foreach (var folderName in activeRules) - { - Outlook.Folder? folder = GetFolder(activeFolder, folderName); - result.Add(new RuleInfo - { - FolderName = folderName, - TrackingId = ExtractTrackingId(folderName), - EmailCount = folder?.Items.Count ?? 0 - }); - } - } - catch { } - - return result; - } - - public void ProcessActiveRules() { } + private Outlook.Folder? GetDefaultFolder(Outlook.OlDefaultFolders type) + => outlookNamespace?.GetDefaultFolder(type) as Outlook.Folder; private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name) { - foreach (Outlook.Folder folder in parent.Folders) - if (folder.Name == name) return folder; + foreach (Outlook.Folder f in parent.Folders) + if (f.Name == name) return f; return (Outlook.Folder)parent.Folders.Add(name); } - private Outlook.Folder? GetFolder(Outlook.Folder parent, string name) + private Outlook.Folder? GetFolder(Outlook.Folder? parent, string name) { - foreach (Outlook.Folder folder in parent.Folders) - if (folder.Name == name) return folder; + if (parent == null) return null; + foreach (Outlook.Folder f in parent.Folders) + if (f.Name == name) return f; return null; } private Outlook.Folder? GetFolderStartingWith(Outlook.Folder parent, string trackingId) { - foreach (Outlook.Folder folder in parent.Folders) - { - string name = folder.Name; - if (name == trackingId || - name.StartsWith(trackingId + " ") || - name.StartsWith(trackingId + "|")) - return folder; - } + foreach (Outlook.Folder f in parent.Folders) + if (f.Name == trackingId || f.Name.StartsWith(trackingId + " ") || f.Name.StartsWith(trackingId + "|")) + return f; return null; } - - public Outlook.MailItem? GetSelectedEmail() - { - if (!EnsureOutlookConnected()) return null; - try - { - Outlook.Explorer activeExplorer = outlookApp!.ActiveExplorer(); - if (activeExplorer == null) return null; - Outlook.Selection selection = activeExplorer.Selection; - if (selection.Count == 0) return null; - return selection[1] as Outlook.MailItem; - } - catch { return null; } - } } } \ No newline at end of file