From dc8d1c138c2ae1803ee7ed45c252dd92ab5c578a Mon Sep 17 00:00:00 2001 From: Wellington Ribeiro Date: Wed, 18 Mar 2026 12:43:44 +0000 Subject: [PATCH] Starting with windows - command to use rules --- OutlookCaseHelper/Form1.cs | 303 ++++++++++++++++++++++++++++- OutlookCaseHelper/OutlookHelper.cs | 48 ++++- 2 files changed, 342 insertions(+), 9 deletions(-) diff --git a/OutlookCaseHelper/Form1.cs b/OutlookCaseHelper/Form1.cs index e290a42..290a049 100644 --- a/OutlookCaseHelper/Form1.cs +++ b/OutlookCaseHelper/Form1.cs @@ -2,24 +2,148 @@ using System; using System.Drawing; using System.Windows.Forms; using System.IO; +using System.Runtime.InteropServices; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Win32; namespace OutlookCaseHelper { public partial class Form1 : Form { + [DllImport("user32.dll")] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + [DllImport("user32.dll")] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + private const int HOTKEY_CREATE = 1; + private const int HOTKEY_REMOVE = 2; + private const uint MOD_ALT = 0x0001; + private const uint MOD_CONTROL = 0x0002; + private const uint MOD_SHIFT = 0x0004; + private NotifyIcon trayIcon = null!; private ContextMenuStrip trayMenu = null!; private OutlookHelper outlookHelper; private System.Windows.Forms.Timer monitorTimer = null!; + private uint hotkeyCreateMod = MOD_ALT; + private uint hotkeyCreateKey = (uint)Keys.F1; + private uint hotkeyRemoveMod = MOD_ALT; + private uint hotkeyRemoveKey = (uint)Keys.F2; + + private readonly string settingsPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "OutlookCaseHelper", "hotkeys.json"); + public Form1() { InitializeComponent(); this.WindowState = FormWindowState.Minimized; this.ShowInTaskbar = false; outlookHelper = new OutlookHelper(); + LoadHotkeySettings(); InitializeTray(); InitializeTimer(); + SetStartupWithWindows(true); + Task.Run(() => outlookHelper.ScanInboxOnStartup()); + } + + 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; } + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + RegisterHotkeys(); + } + + private void RegisterHotkeys() + { + UnregisterHotKey(this.Handle, HOTKEY_CREATE); + UnregisterHotKey(this.Handle, HOTKEY_REMOVE); + RegisterHotKey(this.Handle, HOTKEY_CREATE, hotkeyCreateMod, hotkeyCreateKey); + RegisterHotKey(this.Handle, HOTKEY_REMOVE, hotkeyRemoveMod, hotkeyRemoveKey); + } + + protected override void OnFormClosed(FormClosedEventArgs e) + { + UnregisterHotKey(this.Handle, HOTKEY_CREATE); + UnregisterHotKey(this.Handle, HOTKEY_REMOVE); + base.OnFormClosed(e); + } + + protected override void WndProc(ref Message m) + { + const int WM_HOTKEY = 0x0312; + if (m.Msg == WM_HOTKEY) + { + int id = m.WParam.ToInt32(); + if (id == HOTKEY_CREATE) + ProcessEmail_Click(null, EventArgs.Empty); + else if (id == HOTKEY_REMOVE) + RemoveRuleFromSelected_Click(null, EventArgs.Empty); + } + base.WndProc(ref m); } private void InitializeTray() @@ -30,6 +154,9 @@ namespace OutlookCaseHelper trayMenu.Items.Add("Remove Rule (Selected Email)", null, RemoveRuleFromSelected_Click); trayMenu.Items.Add("Remove Rule (Manual ID)", null, RemoveRule_Click); trayMenu.Items.Add("-"); + trayMenu.Items.Add("Settings", null, Settings_Click); + trayMenu.Items.Add("Start with Windows", null, ToggleStartup_Click); + trayMenu.Items.Add("-"); trayMenu.Items.Add("Exit", null, Exit_Click); trayIcon = new NotifyIcon(); @@ -38,6 +165,49 @@ namespace OutlookCaseHelper trayIcon.Text = "Outlook Case Manager"; trayIcon.Visible = true; trayIcon.MouseDoubleClick += TrayIcon_MouseDoubleClick; + + // Marca o estado atual do startup + using var regKey = Registry.CurrentUser.OpenSubKey( + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", false); + var startupItem = trayMenu.Items[6] as ToolStripMenuItem; + if (startupItem != null) + startupItem.Checked = regKey?.GetValue("OutlookCaseHelper") != null; + } + + private void ToggleStartup_Click(object? sender, EventArgs e) + { + 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; + + MessageBox.Show( + !isEnabled ? "App will now start with Windows." : "App will no longer start with Windows.", + "Settings", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void Settings_Click(object? sender, EventArgs e) + { + var form = new HotkeySettingsForm( + hotkeyCreateMod, hotkeyCreateKey, + hotkeyRemoveMod, hotkeyRemoveKey); + + if (form.ShowDialog() == DialogResult.OK) + { + hotkeyCreateMod = form.CreateMod; + hotkeyCreateKey = form.CreateKey; + hotkeyRemoveMod = form.RemoveMod; + hotkeyRemoveKey = form.RemoveKey; + SaveHotkeySettings(); + RegisterHotkeys(); + MessageBox.Show( + $"Hotkeys updated!\n\nCreate Rule: {form.CreateDescription}\nRemove Rule: {form.RemoveDescription}", + "Settings", MessageBoxButtons.OK, MessageBoxIcon.Information); + } } private void InitializeTimer() @@ -67,7 +237,6 @@ namespace OutlookCaseHelper return; } - // Verifica se já existe regra ativa if (outlookHelper.FindRuleByTrackingId(trackingId) != null) { MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", @@ -75,7 +244,6 @@ namespace OutlookCaseHelper return; } - // Verifica se existe em Closed — reabre sem pedir nome if (outlookHelper.ExistsInClosed(trackingId)) { var triggerEmail = outlookHelper.GetSelectedEmail(); @@ -90,12 +258,10 @@ namespace OutlookCaseHelper return; } - // Caso novo — pede nome 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( @@ -128,7 +294,6 @@ namespace OutlookCaseHelper return; } - // Verifica se existe em Closed — reabre sem pedir nome if (outlookHelper.ExistsInClosed(trackingId)) { bool reopened = outlookHelper.ReopenFromClosed(trackingId); @@ -236,6 +401,134 @@ namespace OutlookCaseHelper Application.Exit(); } + private class HotkeySettingsForm : Form + { + private CheckBox chkCreateAlt, chkCreateCtrl, chkCreateShift; + private CheckBox chkRemoveAlt, chkRemoveCtrl, chkRemoveShift; + private ComboBox cmbCreateKey, cmbRemoveKey; + + public uint CreateMod { get; private set; } + public uint CreateKey { get; private set; } + public uint RemoveMod { get; private set; } + public uint RemoveKey { get; private set; } + public string CreateDescription { get; private set; } = ""; + public string RemoveDescription { get; private set; } = ""; + + private static readonly string[] KeyOptions = { + "F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12", + "0","1","2","3","4","5","6","7","8","9", + "A","B","C","D","E","F","G","H","I","J","K","L","M", + "N","O","P","Q","R","S","T","U","V","W","X","Y","Z" + }; + + public HotkeySettingsForm(uint createMod, uint createKey, uint removeMod, uint removeKey) + { + this.Text = "Hotkey Settings"; + this.Size = new Size(400, 300); + this.MinimumSize = new Size(400, 300); + this.MaximumSize = new Size(400, 300); + this.FormBorderStyle = FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.StartPosition = FormStartPosition.CenterScreen; + + var lblCreate = new Label { Text = "Create Rule shortcut:", Left = 20, Top = 15, Width = 350, Height = 20, Font = new Font(Font, FontStyle.Bold) }; + chkCreateAlt = new CheckBox { Text = "Alt", Left = 20, Top = 40, Width = 60, Checked = (createMod & 0x0001) != 0 }; + chkCreateCtrl = new CheckBox { Text = "Ctrl", Left = 85, Top = 40, Width = 60, Checked = (createMod & 0x0002) != 0 }; + chkCreateShift = new CheckBox { Text = "Shift", Left = 150, Top = 40, Width = 65, Checked = (createMod & 0x0004) != 0 }; + cmbCreateKey = new ComboBox { Left = 220, Top = 38, Width = 100, DropDownStyle = ComboBoxStyle.DropDownList }; + cmbCreateKey.Items.AddRange(KeyOptions); + + var lblRemove = new Label { Text = "Remove Rule shortcut:", Left = 20, Top = 85, Width = 350, Height = 20, Font = new Font(Font, FontStyle.Bold) }; + chkRemoveAlt = new CheckBox { Text = "Alt", Left = 20, Top = 110, Width = 60, Checked = (removeMod & 0x0001) != 0 }; + chkRemoveCtrl = new CheckBox { Text = "Ctrl", Left = 85, Top = 110, Width = 60, Checked = (removeMod & 0x0002) != 0 }; + chkRemoveShift = new CheckBox { Text = "Shift", Left = 150, Top = 110, Width = 65, Checked = (removeMod & 0x0004) != 0 }; + cmbRemoveKey = new ComboBox { Left = 220, Top = 108, Width = 100, DropDownStyle = ComboBoxStyle.DropDownList }; + cmbRemoveKey.Items.AddRange(KeyOptions); + + SelectKey(cmbCreateKey, createKey); + SelectKey(cmbRemoveKey, removeKey); + + var btnOk = new Button { Text = "Save", Left = 200, Top = 220, Width = 80, DialogResult = DialogResult.OK }; + var btnCancel = new Button { Text = "Cancel", Left = 290, Top = 220, Width = 80, DialogResult = DialogResult.Cancel }; + + this.Controls.AddRange(new Control[] { + lblCreate, chkCreateAlt, chkCreateCtrl, chkCreateShift, cmbCreateKey, + lblRemove, chkRemoveAlt, chkRemoveCtrl, chkRemoveShift, cmbRemoveKey, + btnOk, btnCancel + }); + + this.AcceptButton = btnOk; + this.CancelButton = btnCancel; + } + + 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; + + 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); + } + + private uint GetMod(CheckBox alt, CheckBox ctrl, CheckBox shift) + { + uint mod = 0; + if (alt.Checked) mod |= 0x0001; + if (ctrl.Checked) mod |= 0x0002; + if (shift.Checked) mod |= 0x0004; + return mod; + } + + private string GetDescription(CheckBox alt, CheckBox ctrl, CheckBox shift, ComboBox key) + { + var parts = new System.Collections.Generic.List(); + if (ctrl.Checked) parts.Add("Ctrl"); + if (alt.Checked) parts.Add("Alt"); + if (shift.Checked) parts.Add("Shift"); + parts.Add(key.SelectedItem?.ToString() ?? ""); + return string.Join("+", parts); + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + if (this.DialogResult == DialogResult.OK) + { + uint createMod = GetMod(chkCreateAlt, chkCreateCtrl, chkCreateShift); + uint removeMod = GetMod(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift); + + if (createMod == 0 || removeMod == 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; + } + + CreateMod = createMod; + CreateKey = GetKeyCode(cmbCreateKey); + RemoveMod = removeMod; + RemoveKey = GetKeyCode(cmbRemoveKey); + CreateDescription = GetDescription(chkCreateAlt, chkCreateCtrl, chkCreateShift, cmbCreateKey); + RemoveDescription = GetDescription(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift, cmbRemoveKey); + } + base.OnFormClosing(e); + } + } + private class CreateRuleForm : Form { private TextBox txtId; diff --git a/OutlookCaseHelper/OutlookHelper.cs b/OutlookCaseHelper/OutlookHelper.cs index f78de91..e700425 100644 --- a/OutlookCaseHelper/OutlookHelper.cs +++ b/OutlookCaseHelper/OutlookHelper.cs @@ -127,7 +127,6 @@ namespace OutlookCaseHelper return null; } - // Verifica se existe pasta em Closed com este trackingId public bool ExistsInClosed(string trackingId) { try @@ -196,7 +195,6 @@ namespace OutlookCaseHelper catch { return null; } } - // Reabre caso existente em Closed e move o email trigger para lá public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null) { try @@ -216,7 +214,6 @@ namespace OutlookCaseHelper string existingName = closedTracking.Name; closedTracking.MoveTo(activeFolder); - // Move o email que originou a reabertura para a pasta if (triggerEmail != null) { Outlook.Folder? movedFolder = GetFolder(activeFolder, existingName); @@ -304,6 +301,50 @@ namespace OutlookCaseHelper catch { return false; } } + public void ScanInboxOnStartup() + { + if (activeRules.Count == 0) 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); + + Outlook.Items restricted = inboxFolder.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(trackingFolder); + + if (sentFolder != null) + { + Outlook.Items restrictedSent = sentFolder.Items.Restrict(filter); + var toMoveSent = new List(); + foreach (object item in restrictedSent) + if (item is Outlook.MailItem mail) toMoveSent.Add(mail); + foreach (var mail in toMoveSent) + mail.Move(trackingFolder); + } + } + } + catch { } + } + public void ProcessActiveRules() { } private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name) @@ -333,7 +374,6 @@ namespace OutlookCaseHelper return null; } - // Expõe o email selecionado para ser usado no reopen public Outlook.MailItem? GetSelectedEmail() { try