Refactoring cancel buttons, also removing memory leak #1
+62
-27
@@ -37,10 +37,12 @@ namespace OutlookCaseHelper
|
|||||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
"OutlookCaseHelper", "hotkeys.json");
|
"OutlookCaseHelper", "hotkeys.json");
|
||||||
|
|
||||||
|
// Singleton windows
|
||||||
private DashboardForm? _dashboardForm;
|
private DashboardForm? _dashboardForm;
|
||||||
private HotkeySettingsForm? _settingsForm;
|
private HotkeySettingsForm? _settingsForm;
|
||||||
private CreateRuleForm? _createRuleForm;
|
private CreateRuleForm? _createRuleForm;
|
||||||
private InputForm? _removeRuleForm;
|
private InputForm? _removeRuleForm;
|
||||||
|
private AboutForm? _aboutForm;
|
||||||
|
|
||||||
// --- Constructor & Init ---
|
// --- Constructor & Init ---
|
||||||
|
|
||||||
@@ -67,6 +69,18 @@ namespace OutlookCaseHelper
|
|||||||
monitorTimer.Start();
|
monitorTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnFormClosed(FormClosedEventArgs e)
|
||||||
|
{
|
||||||
|
UnregisterHotKey(this.Handle, HOTKEY_CREATE);
|
||||||
|
UnregisterHotKey(this.Handle, HOTKEY_REMOVE);
|
||||||
|
monitorTimer.Stop();
|
||||||
|
monitorTimer.Dispose();
|
||||||
|
outlookHelper.Dispose();
|
||||||
|
trayIcon.Visible = false;
|
||||||
|
trayIcon.Dispose();
|
||||||
|
base.OnFormClosed(e);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Hotkeys ---
|
// --- Hotkeys ---
|
||||||
|
|
||||||
protected override void OnHandleCreated(EventArgs e)
|
protected override void OnHandleCreated(EventArgs e)
|
||||||
@@ -83,13 +97,6 @@ namespace OutlookCaseHelper
|
|||||||
RegisterHotKey(this.Handle, HOTKEY_REMOVE, hotkeyRemoveMod, hotkeyRemoveKey);
|
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)
|
protected override void WndProc(ref Message m)
|
||||||
{
|
{
|
||||||
if (m.Msg == 0x0312)
|
if (m.Msg == 0x0312)
|
||||||
@@ -198,11 +205,27 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
private void Exit_Click(object? sender, EventArgs e)
|
private void Exit_Click(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
monitorTimer.Stop();
|
|
||||||
trayIcon.Visible = false;
|
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Singleton Window Helper ---
|
||||||
|
|
||||||
|
private void ShowSingletonForm<T>(Func<T?> getter, Action<T?> setter, Func<T> create) where T : Form
|
||||||
|
{
|
||||||
|
var field = getter();
|
||||||
|
if (field != null && !field.IsDisposed)
|
||||||
|
{
|
||||||
|
field.BringToFront();
|
||||||
|
field.WindowState = FormWindowState.Normal;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var created = create();
|
||||||
|
setter(created);
|
||||||
|
created.FormClosed += (s, e) => setter(null);
|
||||||
|
created.Show();
|
||||||
|
}
|
||||||
|
|
||||||
// --- Tray Menu Handlers ---
|
// --- Tray Menu Handlers ---
|
||||||
|
|
||||||
private void ToggleStartup_Click(object? sender, EventArgs e)
|
private void ToggleStartup_Click(object? sender, EventArgs e)
|
||||||
@@ -254,13 +277,25 @@ namespace OutlookCaseHelper
|
|||||||
_dashboardForm.WindowState = FormWindowState.Normal;
|
_dashboardForm.WindowState = FormWindowState.Normal;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dashboardForm = new DashboardForm(outlookHelper);
|
_dashboardForm = new DashboardForm(outlookHelper);
|
||||||
_dashboardForm.Owner = this;
|
_dashboardForm.Owner = this;
|
||||||
_dashboardForm.FormClosed += (s, args) => _dashboardForm = null;
|
_dashboardForm.FormClosed += (s, args) => _dashboardForm = null;
|
||||||
_dashboardForm.Show();
|
_dashboardForm.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void About_Click(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (_aboutForm != null && !_aboutForm.IsDisposed)
|
||||||
|
{
|
||||||
|
_aboutForm.BringToFront();
|
||||||
|
_aboutForm.WindowState = FormWindowState.Normal;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_aboutForm = new AboutForm();
|
||||||
|
_aboutForm.FormClosed += (s, args) => _aboutForm = null;
|
||||||
|
_aboutForm.Show();
|
||||||
|
}
|
||||||
|
|
||||||
private void RunAllRules_Click(object? sender, EventArgs e)
|
private void RunAllRules_Click(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -278,8 +313,6 @@ namespace OutlookCaseHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void About_Click(object? sender, EventArgs e) => new AboutForm().ShowDialog();
|
|
||||||
|
|
||||||
// --- Rule Actions ---
|
// --- Rule Actions ---
|
||||||
|
|
||||||
private void ProcessEmail_Click(object? sender, EventArgs e)
|
private void ProcessEmail_Click(object? sender, EventArgs e)
|
||||||
@@ -308,7 +341,6 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
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;
|
||||||
|
|
||||||
HandleCreate(trackingId, ruleForm.FolderName);
|
HandleCreate(trackingId, ruleForm.FolderName);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }
|
catch (Exception ex) { MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); }
|
||||||
@@ -334,7 +366,7 @@ namespace OutlookCaseHelper
|
|||||||
string folderName = _createRuleForm.FolderName;
|
string folderName = _createRuleForm.FolderName;
|
||||||
|
|
||||||
if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
|
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);
|
||||||
else if (outlookHelper.ExistsInClosed(trackingId))
|
else if (outlookHelper.ExistsInClosed(trackingId))
|
||||||
HandleReopen(trackingId);
|
HandleReopen(trackingId);
|
||||||
else
|
else
|
||||||
@@ -423,7 +455,7 @@ namespace OutlookCaseHelper
|
|||||||
private void HandleRemove(string folderName)
|
private void HandleRemove(string folderName)
|
||||||
{
|
{
|
||||||
if (outlookHelper.RemoveRuleAndMoveToClosed(folderName))
|
if (outlookHelper.RemoveRuleAndMoveToClosed(folderName))
|
||||||
MessageBox.Show($"Rule removed!\n\nFolder moved to: Inbox > Cases > Closed\nFolder: {folderName}\nMonitoring stopped.",
|
MessageBox.Show($"Rule removed!\n\nFolder moved to Closed.\nFolder: {folderName}\nMonitoring stopped.",
|
||||||
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
"Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
else
|
else
|
||||||
MessageBox.Show("Error removing rule. Check if folder exists.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show("Error removing rule. Check if folder exists.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
@@ -513,10 +545,7 @@ namespace OutlookCaseHelper
|
|||||||
string folderName = ruleForm.FolderName;
|
string folderName = ruleForm.FolderName;
|
||||||
|
|
||||||
if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
|
if (outlookHelper.FindRuleByTrackingId(trackingId) != null)
|
||||||
{
|
{ MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; }
|
||||||
MessageBox.Show($"Rule for TrackingID#{trackingId} already exists!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outlookHelper.ExistsInClosed(trackingId))
|
if (outlookHelper.ExistsInClosed(trackingId))
|
||||||
{
|
{
|
||||||
@@ -558,8 +587,10 @@ namespace OutlookCaseHelper
|
|||||||
var txt = new TextBox { Left = 20, Top = 40, Width = 370, Height = 24, Text = rule.FolderName };
|
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 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 };
|
var btnCancel = new Button { Text = "Cancel", Left = 300, Top = 80, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
btnCancel.Click += (s, e) => inputForm.Close();
|
||||||
inputForm.Controls.AddRange(new Control[] { lbl, txt, btnOk, btnCancel });
|
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;
|
if (inputForm.ShowDialog() != DialogResult.OK) return;
|
||||||
string newName = txt.Text.Trim();
|
string newName = txt.Text.Trim();
|
||||||
@@ -580,11 +611,11 @@ namespace OutlookCaseHelper
|
|||||||
if (rule == null) return;
|
if (rule == null) return;
|
||||||
|
|
||||||
if (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.",
|
$"Are you sure you want to close this case?\n\nFolder: {rule.FolderName}\n\nThe folder will be moved to Closed.",
|
||||||
"Close Case", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return;
|
"Close Case", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) return;
|
||||||
|
|
||||||
if (outlookHelper.RemoveRuleAndMoveToClosed(rule.FolderName))
|
if (outlookHelper.RemoveRuleAndMoveToClosed(rule.FolderName))
|
||||||
{ MessageBox.Show("Case closed!\n\nFolder moved to: Inbox > Cases > Closed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); }
|
{ MessageBox.Show("Case closed!\n\nFolder moved to Closed.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); LoadRules(); }
|
||||||
else
|
else
|
||||||
MessageBox.Show("Error closing case.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
MessageBox.Show("Error closing case.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
}
|
}
|
||||||
@@ -668,6 +699,7 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
var btnOk = new Button { Text = "Save", Left = 216, Top = 200, Width = 80, DialogResult = DialogResult.OK };
|
var btnOk = new Button { Text = "Save", Left = 216, Top = 200, Width = 80, DialogResult = DialogResult.OK };
|
||||||
var btnCancel = new Button { Text = "Cancel", Left = 304, Top = 200, Width = 80, DialogResult = DialogResult.Cancel };
|
var btnCancel = new Button { Text = "Cancel", Left = 304, Top = 200, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
|
|
||||||
this.Controls.AddRange(new Control[] {
|
this.Controls.AddRange(new Control[] {
|
||||||
lblCreate, chkCreateAlt, chkCreateCtrl, chkCreateShift, cmbCreateKey,
|
lblCreate, chkCreateAlt, chkCreateCtrl, chkCreateShift, cmbCreateKey,
|
||||||
@@ -720,7 +752,8 @@ namespace OutlookCaseHelper
|
|||||||
uint rm = GetMod(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift);
|
uint rm = GetMod(chkRemoveAlt, chkRemoveCtrl, chkRemoveShift);
|
||||||
if (cm == 0 || rm == 0)
|
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);
|
MessageBox.Show("Please select at least one modifier (Alt, Ctrl or Shift) for each shortcut.",
|
||||||
|
"Validation", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||||
e.Cancel = true; return;
|
e.Cancel = true; return;
|
||||||
}
|
}
|
||||||
CreateMod = cm; CreateKey = GetKeyCode(cmbCreateKey);
|
CreateMod = cm; CreateKey = GetKeyCode(cmbCreateKey);
|
||||||
@@ -761,6 +794,7 @@ namespace OutlookCaseHelper
|
|||||||
|
|
||||||
var btnOk = new Button { Text = "OK", Left = 220, Top = 158, Width = 80, DialogResult = DialogResult.OK };
|
var btnOk = new Button { Text = "OK", Left = 220, Top = 158, Width = 80, DialogResult = DialogResult.OK };
|
||||||
var btnCancel = new Button { Text = "Cancel", Left = 310, Top = 158, Width = 80, DialogResult = DialogResult.Cancel };
|
var btnCancel = new Button { Text = "Cancel", Left = 310, Top = 158, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
|
|
||||||
txtId.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
txtId.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
||||||
txtName.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
txtName.TextChanged += (s, e) => UpdatePreview(txtId.Text.Trim());
|
||||||
@@ -812,6 +846,7 @@ namespace OutlookCaseHelper
|
|||||||
txtInput = new TextBox { Left = 20, Top = 45, Width = 330, Height = 24 };
|
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 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 };
|
var btnCancel = new Button { Text = "Cancel", Left = 245, Top = 80, Width = 80, DialogResult = DialogResult.Cancel };
|
||||||
|
btnCancel.Click += (s, e) => this.Close();
|
||||||
|
|
||||||
this.Controls.AddRange(new Control[] { label, txtInput, btnOk, btnCancel });
|
this.Controls.AddRange(new Control[] { label, txtInput, btnOk, btnCancel });
|
||||||
this.AcceptButton = btnOk;
|
this.AcceptButton = btnOk;
|
||||||
@@ -848,15 +883,15 @@ namespace OutlookCaseHelper
|
|||||||
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 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 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) };
|
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) };
|
||||||
|
|
||||||
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) };
|
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) };
|
||||||
|
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 };
|
||||||
|
|
||||||
lblEmail.LinkClicked += (s, e) =>
|
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 { }
|
||||||
};
|
};
|
||||||
|
btnClose.Click += (s, e) => this.Close();
|
||||||
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.Controls.AddRange(new Control[] { pictureBox, lblName, lblVersion, lblDate, lblDesc, separator, lblCreatedBy, lblEmail, lblSuggestions, btnClose });
|
||||||
this.CancelButton = btnClose;
|
this.CancelButton = btnClose;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Outlook = Microsoft.Office.Interop.Outlook;
|
|||||||
|
|
||||||
namespace OutlookCaseHelper
|
namespace OutlookCaseHelper
|
||||||
{
|
{
|
||||||
public class OutlookHelper
|
public class OutlookHelper : IDisposable
|
||||||
{
|
{
|
||||||
private Outlook.Application? outlookApp;
|
private Outlook.Application? outlookApp;
|
||||||
private Outlook.NameSpace? outlookNamespace;
|
private Outlook.NameSpace? outlookNamespace;
|
||||||
@@ -16,6 +16,7 @@ namespace OutlookCaseHelper
|
|||||||
private readonly string rulesFilePath;
|
private readonly string rulesFilePath;
|
||||||
private Outlook.Items? inboxItems;
|
private Outlook.Items? inboxItems;
|
||||||
private Outlook.Items? sentItems;
|
private Outlook.Items? sentItems;
|
||||||
|
private bool disposed = false;
|
||||||
|
|
||||||
public class RuleInfo
|
public class RuleInfo
|
||||||
{
|
{
|
||||||
@@ -28,18 +29,53 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
rulesFilePath = Path.Combine(
|
rulesFilePath = Path.Combine(
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
"OutlookCaseHelper",
|
"OutlookCaseHelper", "active_rules.json");
|
||||||
"active_rules.json");
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(rulesFilePath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(rulesFilePath)!);
|
||||||
LoadRules();
|
LoadRules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Dispose ---
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (disposed) return;
|
||||||
|
disposed = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (inboxItems != null)
|
||||||
|
{
|
||||||
|
inboxItems.ItemAdd -= OnEmailReceived;
|
||||||
|
System.Runtime.InteropServices.Marshal.ReleaseComObject(inboxItems);
|
||||||
|
inboxItems = null;
|
||||||
|
}
|
||||||
|
if (sentItems != null)
|
||||||
|
{
|
||||||
|
sentItems.ItemAdd -= OnEmailSent;
|
||||||
|
System.Runtime.InteropServices.Marshal.ReleaseComObject(sentItems);
|
||||||
|
sentItems = null;
|
||||||
|
}
|
||||||
|
if (outlookNamespace != null)
|
||||||
|
{
|
||||||
|
System.Runtime.InteropServices.Marshal.ReleaseComObject(outlookNamespace);
|
||||||
|
outlookNamespace = null;
|
||||||
|
}
|
||||||
|
if (outlookApp != null)
|
||||||
|
{
|
||||||
|
System.Runtime.InteropServices.Marshal.ReleaseComObject(outlookApp);
|
||||||
|
outlookApp = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
// --- Outlook Connection ---
|
// --- Outlook Connection ---
|
||||||
|
|
||||||
private bool EnsureOutlookConnected()
|
private bool EnsureOutlookConnected()
|
||||||
{
|
{
|
||||||
if (outlookApp != null && outlookNamespace != null) return true;
|
if (outlookApp != null && outlookNamespace != null) return true;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (System.Diagnostics.Process.GetProcessesByName("OUTLOOK").Length == 0)
|
if (System.Diagnostics.Process.GetProcessesByName("OUTLOOK").Length == 0)
|
||||||
@@ -84,20 +120,18 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (outlookNamespace == null) return;
|
if (outlookNamespace == null || activeRules.Count == 0) return;
|
||||||
if (activeRules.Count == 0) return;
|
if (item is not Outlook.MailItem mail || mail.Subject == null) return;
|
||||||
if (item is not Outlook.MailItem mail) return;
|
|
||||||
if (mail.Subject == null) return;
|
|
||||||
|
|
||||||
foreach (var folderName in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
string trackingId = ExtractTrackingId(folderName);
|
string trackingId = ExtractTrackingId(folderName);
|
||||||
if (!mail.Subject.Contains($"TrackingID#{trackingId}")) continue;
|
if (!mail.Subject.Contains($"TrackingID#{trackingId}")) continue;
|
||||||
|
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
if (inbox == null) return;
|
if (activeFolder == null) return;
|
||||||
|
|
||||||
var target = GetOrCreateFolder(GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active"), folderName);
|
var target = GetOrCreateFolder(activeFolder, folderName);
|
||||||
mail.Move(target);
|
mail.Move(target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -168,9 +202,7 @@ namespace OutlookCaseHelper
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!EnsureOutlookConnected()) return false;
|
if (!EnsureOutlookConnected()) return false;
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var closed = FindFolderByNameAnywhere("Closed");
|
||||||
if (inbox == null) return false;
|
|
||||||
var closed = GetFolder(GetFolder(inbox, "Cases"), "Closed");
|
|
||||||
return closed != null && GetFolderStartingWith(closed, trackingId) != null;
|
return closed != null && GetFolderStartingWith(closed, trackingId) != null;
|
||||||
}
|
}
|
||||||
catch { return false; }
|
catch { return false; }
|
||||||
@@ -180,25 +212,35 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
if (!EnsureOutlookConnected()) return false;
|
if (!EnsureOutlookConnected()) return false;
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
|
if (activeFolder == null)
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
if (inbox == null) return false;
|
if (inbox == null) return false;
|
||||||
|
var cases = GetOrCreateFolder(inbox, "Cases");
|
||||||
|
activeFolder = GetOrCreateFolder(cases, "Active");
|
||||||
|
}
|
||||||
|
|
||||||
var target = GetOrCreateFolder(GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active"), folderName);
|
var target = GetOrCreateFolder(activeFolder, folderName);
|
||||||
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
||||||
|
|
||||||
MoveFilteredEmails(inbox, filter, target);
|
var inbox2 = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
|
|
||||||
var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
|
var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
|
||||||
|
|
||||||
|
if (inbox2 != null) MoveFilteredEmails(inbox2, filter, target);
|
||||||
if (sent != null) MoveFilteredEmails(sent, filter, target);
|
if (sent != null) MoveFilteredEmails(sent, filter, target);
|
||||||
|
|
||||||
foreach (Outlook.Folder folder in inbox.Parent.Folders)
|
if (inbox2 != null)
|
||||||
|
{
|
||||||
|
foreach (Outlook.Folder folder in inbox2.Parent.Folders)
|
||||||
{
|
{
|
||||||
if (folder.Name != "Cases" &&
|
if (folder.Name != "Cases" &&
|
||||||
folder.EntryID != inbox.EntryID &&
|
folder.EntryID != inbox2.EntryID &&
|
||||||
folder.EntryID != sent?.EntryID)
|
folder.EntryID != sent?.EntryID)
|
||||||
try { MoveFilteredEmails(folder, filter, target); } catch { }
|
try { MoveFilteredEmails(folder, filter, target); } catch { }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
activeRules.Add(folderName);
|
activeRules.Add(folderName);
|
||||||
SaveRules();
|
SaveRules();
|
||||||
@@ -216,15 +258,22 @@ namespace OutlookCaseHelper
|
|||||||
if (!EnsureOutlookConnected()) return false;
|
if (!EnsureOutlookConnected()) return false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
if (inbox == null) return false;
|
if (activeFolder == null) return false;
|
||||||
|
|
||||||
var cases = GetFolder(inbox, "Cases");
|
var folder = GetFolder(activeFolder, folderName);
|
||||||
var active = GetFolder(cases, "Active");
|
|
||||||
var folder = GetFolder(active, folderName);
|
|
||||||
if (folder == null) return false;
|
if (folder == null) return false;
|
||||||
|
|
||||||
folder.MoveTo(GetOrCreateFolder(cases!, "Closed"));
|
var closedFolder = FindFolderByNameAnywhere("Closed");
|
||||||
|
if (closedFolder == null)
|
||||||
|
{
|
||||||
|
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
|
if (inbox == null) return false;
|
||||||
|
var cases = GetOrCreateFolder(inbox, "Cases");
|
||||||
|
closedFolder = GetOrCreateFolder(cases, "Closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.MoveTo(closedFolder);
|
||||||
activeRules.Remove(folderName);
|
activeRules.Remove(folderName);
|
||||||
SaveRules();
|
SaveRules();
|
||||||
return true;
|
return true;
|
||||||
@@ -237,9 +286,8 @@ namespace OutlookCaseHelper
|
|||||||
if (!EnsureOutlookConnected()) return false;
|
if (!EnsureOutlookConnected()) return false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
var active = GetFolder(GetFolder(inbox, "Cases"), "Active");
|
var folder = GetFolder(activeFolder, oldFolderName);
|
||||||
var folder = GetFolder(active, oldFolderName);
|
|
||||||
if (folder == null) return false;
|
if (folder == null) return false;
|
||||||
|
|
||||||
folder.Name = newFolderName;
|
folder.Name = newFolderName;
|
||||||
@@ -256,20 +304,24 @@ namespace OutlookCaseHelper
|
|||||||
if (!EnsureOutlookConnected()) return false;
|
if (!EnsureOutlookConnected()) return false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var closedFolder = FindFolderByNameAnywhere("Closed");
|
||||||
if (inbox == null) return false;
|
if (closedFolder == null) return false;
|
||||||
|
|
||||||
var cases = GetOrCreateFolder(inbox, "Cases");
|
var closedTracking = GetFolderStartingWith(closedFolder, trackingId);
|
||||||
var active = GetOrCreateFolder(cases, "Active");
|
|
||||||
var closed = GetFolder(cases, "Closed");
|
|
||||||
if (closed == null) return false;
|
|
||||||
|
|
||||||
var closedTracking = GetFolderStartingWith(closed, trackingId);
|
|
||||||
if (closedTracking == null) return false;
|
if (closedTracking == null) return false;
|
||||||
|
|
||||||
string existingName = closedTracking.Name;
|
string existingName = closedTracking.Name;
|
||||||
var existingActive = GetFolder(active, existingName);
|
|
||||||
|
|
||||||
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
|
if (activeFolder == null)
|
||||||
|
{
|
||||||
|
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
|
if (inbox == null) return false;
|
||||||
|
var cases = GetOrCreateFolder(inbox, "Cases");
|
||||||
|
activeFolder = GetOrCreateFolder(cases, "Active");
|
||||||
|
}
|
||||||
|
|
||||||
|
var existingActive = GetFolder(activeFolder, existingName);
|
||||||
if (existingActive != null)
|
if (existingActive != null)
|
||||||
{
|
{
|
||||||
var toMove = new List<Outlook.MailItem>();
|
var toMove = new List<Outlook.MailItem>();
|
||||||
@@ -280,12 +332,12 @@ namespace OutlookCaseHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
closedTracking.MoveTo(active);
|
closedTracking.MoveTo(activeFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var target = GetFolder(active, existingName);
|
var target = GetFolder(activeFolder, existingName);
|
||||||
if (triggerEmail != null && target != null)
|
if (triggerEmail != null && target != null)
|
||||||
triggerEmail.Move(target);
|
triggerEmail.Move(target);
|
||||||
}
|
}
|
||||||
@@ -299,8 +351,7 @@ namespace OutlookCaseHelper
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var active = FindFolderByNameAnywhere("Active");
|
||||||
var active = GetFolder(GetFolder(inbox, "Cases"), "Active");
|
|
||||||
var moved = GetFolderStartingWith(active!, trackingId);
|
var moved = GetFolderStartingWith(active!, trackingId);
|
||||||
if (moved != null) { activeRules.Add(moved.Name); SaveRules(); return true; }
|
if (moved != null) { activeRules.Add(moved.Name); SaveRules(); return true; }
|
||||||
}
|
}
|
||||||
@@ -320,13 +371,18 @@ namespace OutlookCaseHelper
|
|||||||
var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
|
var sent = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail);
|
||||||
if (inbox == null) return;
|
if (inbox == null) return;
|
||||||
|
|
||||||
var active = GetOrCreateFolder(GetOrCreateFolder(inbox, "Cases"), "Active");
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
|
if (activeFolder == null)
|
||||||
|
{
|
||||||
|
var cases = GetOrCreateFolder(inbox, "Cases");
|
||||||
|
activeFolder = GetOrCreateFolder(cases, "Active");
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var folderName in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
string trackingId = ExtractTrackingId(folderName);
|
string trackingId = ExtractTrackingId(folderName);
|
||||||
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
||||||
var target = GetOrCreateFolder(active, folderName);
|
var target = GetOrCreateFolder(activeFolder, folderName);
|
||||||
|
|
||||||
MoveFilteredEmails(inbox, filter, target);
|
MoveFilteredEmails(inbox, filter, target);
|
||||||
if (sent != null) MoveFilteredEmails(sent, filter, target);
|
if (sent != null) MoveFilteredEmails(sent, filter, target);
|
||||||
@@ -343,18 +399,22 @@ namespace OutlookCaseHelper
|
|||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
if (inbox == null) return;
|
if (inbox == null) return;
|
||||||
|
|
||||||
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
|
if (activeFolder == null)
|
||||||
|
{
|
||||||
var cases = GetOrCreateFolder(inbox, "Cases");
|
var cases = GetOrCreateFolder(inbox, "Cases");
|
||||||
var active = GetOrCreateFolder(cases, "Active");
|
activeFolder = GetOrCreateFolder(cases, "Active");
|
||||||
|
}
|
||||||
|
|
||||||
var allFolders = new List<Outlook.Folder>();
|
var allFolders = new List<Outlook.Folder>();
|
||||||
if (inbox.Parent is Outlook.Folder root)
|
if (inbox.Parent is Outlook.Folder root)
|
||||||
GetAllFolders(root, allFolders, cases.EntryID);
|
GetAllFolders(root, allFolders, activeFolder.EntryID);
|
||||||
|
|
||||||
foreach (var folderName in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
string trackingId = ExtractTrackingId(folderName);
|
string trackingId = ExtractTrackingId(folderName);
|
||||||
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
string filter = $"@SQL=\"urn:schemas:httpmail:subject\" LIKE '%TrackingID#{trackingId}%'";
|
||||||
var target = GetOrCreateFolder(active, folderName);
|
var target = GetOrCreateFolder(activeFolder, folderName);
|
||||||
|
|
||||||
foreach (var folder in allFolders)
|
foreach (var folder in allFolders)
|
||||||
try { MoveFilteredEmails(folder, filter, target); } catch { }
|
try { MoveFilteredEmails(folder, filter, target); } catch { }
|
||||||
@@ -369,13 +429,12 @@ namespace OutlookCaseHelper
|
|||||||
if (!EnsureOutlookConnected()) return result;
|
if (!EnsureOutlookConnected()) return result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
var activeFolder = FindFolderByNameAnywhere("Active");
|
||||||
var active = GetFolder(GetFolder(inbox, "Cases"), "Active");
|
if (activeFolder == null) return result;
|
||||||
if (active == null) return result;
|
|
||||||
|
|
||||||
foreach (var folderName in activeRules)
|
foreach (var folderName in activeRules)
|
||||||
{
|
{
|
||||||
var folder = GetFolder(active, folderName);
|
var folder = GetFolder(activeFolder, folderName);
|
||||||
result.Add(new RuleInfo
|
result.Add(new RuleInfo
|
||||||
{
|
{
|
||||||
FolderName = folderName,
|
FolderName = folderName,
|
||||||
@@ -388,6 +447,34 @@ namespace OutlookCaseHelper
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Folder Search (any hierarchy level) ---
|
||||||
|
|
||||||
|
private Outlook.Folder? FindFolderByNameAnywhere(string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var inbox = GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
|
||||||
|
if (inbox?.Parent is not Outlook.Folder root) return null;
|
||||||
|
return SearchFolderRecursive(root, name);
|
||||||
|
}
|
||||||
|
catch { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Outlook.Folder? SearchFolderRecursive(Outlook.Folder parent, string name)
|
||||||
|
{
|
||||||
|
foreach (Outlook.Folder folder in parent.Folders)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (folder.Name == name) return folder;
|
||||||
|
var found = SearchFolderRecursive(folder, name);
|
||||||
|
if (found != null) return found;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// --- Helpers ---
|
// --- Helpers ---
|
||||||
|
|
||||||
private string ExtractTrackingId(string folderName)
|
private string ExtractTrackingId(string folderName)
|
||||||
|
|||||||
Reference in New Issue
Block a user