Starting with windows - command to use rules

This commit is contained in:
2026-03-18 12:43:44 +00:00
parent f4e456ed92
commit dc8d1c138c
2 changed files with 342 additions and 9 deletions
+298 -5
View File
@@ -2,24 +2,148 @@ using System;
using System.Drawing; using System.Drawing;
using System.Windows.Forms; using System.Windows.Forms;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Win32;
namespace OutlookCaseHelper namespace OutlookCaseHelper
{ {
public partial class Form1 : Form 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 NotifyIcon trayIcon = null!;
private ContextMenuStrip trayMenu = null!; private ContextMenuStrip trayMenu = null!;
private OutlookHelper outlookHelper; private OutlookHelper outlookHelper;
private System.Windows.Forms.Timer monitorTimer = null!; 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() public Form1()
{ {
InitializeComponent(); InitializeComponent();
this.WindowState = FormWindowState.Minimized; this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false; this.ShowInTaskbar = false;
outlookHelper = new OutlookHelper(); outlookHelper = new OutlookHelper();
LoadHotkeySettings();
InitializeTray(); InitializeTray();
InitializeTimer(); 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<HotkeySettings>(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() private void InitializeTray()
@@ -30,6 +154,9 @@ namespace OutlookCaseHelper
trayMenu.Items.Add("Remove Rule (Selected Email)", null, RemoveRuleFromSelected_Click); trayMenu.Items.Add("Remove Rule (Selected Email)", null, RemoveRuleFromSelected_Click);
trayMenu.Items.Add("Remove Rule (Manual ID)", null, RemoveRule_Click); trayMenu.Items.Add("Remove Rule (Manual ID)", null, RemoveRule_Click);
trayMenu.Items.Add("-"); 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); trayMenu.Items.Add("Exit", null, Exit_Click);
trayIcon = new NotifyIcon(); trayIcon = new NotifyIcon();
@@ -38,6 +165,49 @@ namespace OutlookCaseHelper
trayIcon.Text = "Outlook Case Manager"; trayIcon.Text = "Outlook Case Manager";
trayIcon.Visible = true; trayIcon.Visible = true;
trayIcon.MouseDoubleClick += TrayIcon_MouseDoubleClick; 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() private void InitializeTimer()
@@ -67,7 +237,6 @@ namespace OutlookCaseHelper
return; return;
} }
// Verifica se já existe regra ativa
if (outlookHelper.FindRuleByTrackingId(trackingId) != null) if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
{ {
MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!",
@@ -75,7 +244,6 @@ namespace OutlookCaseHelper
return; return;
} }
// Verifica se existe em Closed — reabre sem pedir nome
if (outlookHelper.ExistsInClosed(trackingId)) if (outlookHelper.ExistsInClosed(trackingId))
{ {
var triggerEmail = outlookHelper.GetSelectedEmail(); var triggerEmail = outlookHelper.GetSelectedEmail();
@@ -90,12 +258,10 @@ namespace OutlookCaseHelper
return; return;
} }
// Caso novo — pede nome
var ruleForm = new CreateRuleForm(trackingId, readonlyId: true); var ruleForm = new CreateRuleForm(trackingId, readonlyId: true);
if (ruleForm.ShowDialog() != DialogResult.OK) return; if (ruleForm.ShowDialog() != DialogResult.OK) return;
string folderName = ruleForm.FolderName; string folderName = ruleForm.FolderName;
bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName); bool success = outlookHelper.CreateFolderAndMoveEmails(trackingId, folderName);
if (success) if (success)
MessageBox.Show( MessageBox.Show(
@@ -128,7 +294,6 @@ namespace OutlookCaseHelper
return; return;
} }
// Verifica se existe em Closed — reabre sem pedir nome
if (outlookHelper.ExistsInClosed(trackingId)) if (outlookHelper.ExistsInClosed(trackingId))
{ {
bool reopened = outlookHelper.ReopenFromClosed(trackingId); bool reopened = outlookHelper.ReopenFromClosed(trackingId);
@@ -236,6 +401,134 @@ namespace OutlookCaseHelper
Application.Exit(); 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<string>();
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 class CreateRuleForm : Form
{ {
private TextBox txtId; private TextBox txtId;
+44 -4
View File
@@ -127,7 +127,6 @@ namespace OutlookCaseHelper
return null; return null;
} }
// Verifica se existe pasta em Closed com este trackingId
public bool ExistsInClosed(string trackingId) public bool ExistsInClosed(string trackingId)
{ {
try try
@@ -196,7 +195,6 @@ namespace OutlookCaseHelper
catch { return null; } catch { return null; }
} }
// Reabre caso existente em Closed e move o email trigger para lá
public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null) public bool ReopenFromClosed(string trackingId, Outlook.MailItem? triggerEmail = null)
{ {
try try
@@ -216,7 +214,6 @@ namespace OutlookCaseHelper
string existingName = closedTracking.Name; string existingName = closedTracking.Name;
closedTracking.MoveTo(activeFolder); closedTracking.MoveTo(activeFolder);
// Move o email que originou a reabertura para a pasta
if (triggerEmail != null) if (triggerEmail != null)
{ {
Outlook.Folder? movedFolder = GetFolder(activeFolder, existingName); Outlook.Folder? movedFolder = GetFolder(activeFolder, existingName);
@@ -304,6 +301,50 @@ namespace OutlookCaseHelper
catch { return false; } 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<Outlook.MailItem>();
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<Outlook.MailItem>();
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() { } public void ProcessActiveRules() { }
private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name) private Outlook.Folder GetOrCreateFolder(Outlook.Folder parent, string name)
@@ -333,7 +374,6 @@ namespace OutlookCaseHelper
return null; return null;
} }
// Expõe o email selecionado para ser usado no reopen
public Outlook.MailItem? GetSelectedEmail() public Outlook.MailItem? GetSelectedEmail()
{ {
try try