diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs
index 1281880..4970a03 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs
@@ -71,6 +71,8 @@ namespace Acacia.Features.SharedFolders
// Private shared appointment
SetupPrivateAppointmentSuppression();
+
+ SetupHierarchyChangeSuppression();
}
#region UI
@@ -288,5 +290,119 @@ namespace Acacia.Features.SharedFolders
}
#endregion
+
+ #region Hierarchy changes
+
+ private class SharedFolderRegistration : FolderRegistration
+ {
+ public SharedFolderRegistration(Feature feature) : base(feature)
+ {
+ }
+
+ public override bool IsApplicable(IFolder folder)
+ {
+ if (folder.SyncId != null && folder.SyncId.IsShared)
+ return true;
+
+ using (IFolder parent = folder.Parent)
+ {
+ if (parent != null)
+ return IsApplicable(parent);
+ }
+
+ return false;
+ }
+ }
+
+ private void SetupHierarchyChangeSuppression()
+ {
+ Watcher.WatchFolder(new SharedFolderRegistration(this),
+ OnSharedFolderDiscovered,
+ OnSharedFolderChanged,
+ OnSharedFolderRemoved);
+ }
+
+ private void OnSharedFolderDiscovered(IFolder folder)
+ {
+ Logger.Instance.Trace(this, "Shared folder discovered: {0} - {1}", folder.Name, folder.SyncId);
+ if (folder.SyncId == null || !folder.SyncId.IsShared)
+ {
+ Logger.Instance.Warning(this, "Local folder created in shared folder, deleting: {0} - {1}", folder.Name, folder.SyncId);
+ // This is a new, locally created folder. Warn and remove
+ MessageBox.Show(ThisAddIn.Instance.Window,
+ Properties.Resources.SharedFolders_LocalFolder_Body,
+ Properties.Resources.SharedFolders_LocalFolder_Title,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning
+ );
+ folder.Delete();
+ Logger.Instance.Warning(this, "Local folder created in shared folder, deleted: {0} - {1}", folder.Name, folder.SyncId);
+ }
+ else
+ {
+ folder.BeforeFolderMove += Folder_BeforeFolderMove;
+
+ // Check if it was renamed before the events were fully set up
+ CheckSharedFolderRename(folder);
+ }
+ }
+
+ private void Folder_BeforeFolderMove(IFolder src, IFolder moveTo, ref bool cancel)
+ {
+ Logger.Instance.Fatal(this, "SHARED FOLDER MOVE: {0}", moveTo.Name);
+
+ MessageBox.Show(ThisAddIn.Instance.Window,
+ Properties.Resources.SharedFolders_LocalFolder_Body,
+ Properties.Resources.SharedFolders_LocalFolder_Title,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning
+ );
+ cancel = true;
+ }
+
+ private void OnSharedFolderChanged(IFolder folder)
+ {
+ Logger.Instance.Trace(this, "Shared folder changed: {0} - {1}", folder.Name, folder.SyncId);
+ CheckSharedFolderRename(folder);
+ }
+
+ private void CheckSharedFolderRename(IFolder folder)
+ {
+ if (folder.SyncId != null && folder.SyncId.IsShared)
+ {
+ string originalName = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_NAME);
+ // The folder.name property is sometimes cached, check against the MAPI property
+ string currentName = (string)folder.GetProperty(OutlookConstants.PR_DISPLAY_NAME_W);
+ if (currentName != originalName)
+ {
+ Logger.Instance.Warning(this, "Shared folder renamed, renaming back: {0} - {1} - {2}", folder.Name, folder.SyncId, originalName);
+ // This is a locally renamed folder. Warn and rename back
+ MessageBox.Show(ThisAddIn.Instance.Window,
+ Properties.Resources.SharedFolders_LocalFolder_Body,
+ Properties.Resources.SharedFolders_LocalFolder_Title,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning
+ );
+ // Update both name and display name
+ folder.Name = originalName;
+ folder.SetProperty(OutlookConstants.PR_DISPLAY_NAME_W, originalName);
+ Logger.Instance.Warning(this, "Shared folder renamed, renamed back: {0} - {1} - {2}", folder.Name, folder.SyncId, originalName);
+ }
+ }
+ }
+
+ private void OnSharedFolderRemoved(IFolder folder)
+ {
+ Logger.Instance.Fatal(this, "Shared folder removed, undeleting: {0}", folder.Name);
+ MessageBox.Show(ThisAddIn.Instance.Window,
+ Properties.Resources.SharedFolders_LocalFolder_Body,
+ Properties.Resources.SharedFolders_LocalFolder_Title,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Warning
+ );
+ //folder.Delete();
+ }
+
+ #endregion
}
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
index a6d0908..c3bcfe8 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
@@ -84,6 +84,7 @@ namespace Acacia
public const string PR_ATTR_HIDDEN = PROP + "10F4" + PT_BOOLEAN;
public const string PR_DISPLAY_NAME = PROP + "3001" + PT_STRING8;
+ public const string PR_DISPLAY_NAME_W = PROP + "3001" + PT_UNICODE;
public const string PR_SUBJECT = PROP + "0037" + PT_UNICODE;
@@ -138,6 +139,7 @@ namespace Acacia
public const string PR_ZPUSH_SYNC_ID = PROP + "6A18" + PT_STRING8;
public const string PR_ZPUSH_FOLDER_ID = PROP + "6A19" + PT_STRING8;
public const string PR_ZPUSH_MESSAGE_ID = PROP + "6B20" + PT_STRING8;
+ public const string PR_ZPUSH_NAME = PROP + "6915" + PT_UNICODE;
// TODO: names for these, use MFCMAPI
public const string PR_EAS_SYNC1 = PROP + "6A17" + PT_BOOLEAN;
@@ -146,7 +148,6 @@ namespace Acacia
public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG;
public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN;
public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG;
- public const string PR_EAS_NAME = PROP + "6915" + PT_UNICODE;
public enum SyncType
{
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
index fe4a3e3..1e86f86 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
@@ -1075,6 +1075,24 @@ namespace Acacia.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to Modifying shared folders locally is not supported. Please use the 'Shared Folders' dialog to modify these folders..
+ ///
+ internal static string SharedFolders_LocalFolder_Body {
+ get {
+ return ResourceManager.GetString("SharedFolders_LocalFolder_Body", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Shared folders.
+ ///
+ internal static string SharedFolders_LocalFolder_Title {
+ get {
+ return ResourceManager.GetString("SharedFolders_LocalFolder_Title", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to No shared folders are available or you do not have permissions to view the root of the inbox..
///
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
index 3013c37..0c60b45 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
@@ -514,4 +514,10 @@
Private event
+
+ Modifying shared folders locally is not supported. Please use the 'Shared Folders' dialog to modify these folders.
+
+
+ Shared folders
+
\ No newline at end of file
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs
index e79b7ff..5249477 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs
@@ -24,6 +24,7 @@ using System.Threading.Tasks;
namespace Acacia.Stubs
{
public delegate void IFolder_BeforeItemMove(IFolder src, IItem item, IFolder target, ref bool cancel);
+ public delegate void IFolder_BeforeFolderMove(IFolder src, IFolder moveTo, ref bool cancel);
public interface IFolder : IBase
{
@@ -95,6 +96,7 @@ namespace Acacia.Stubs
#region Events
event IFolder_BeforeItemMove BeforeItemMove;
+ event IFolder_BeforeFolderMove BeforeFolderMove;
#endregion
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs
index 0fe7af6..e152ffd 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs
@@ -341,6 +341,52 @@ namespace Acacia.Stubs.OutlookWrappers
}
}
+ private IFolder_BeforeFolderMove _beforeFolderMove;
+ public event IFolder_BeforeFolderMove BeforeFolderMove
+ {
+ add
+ {
+ if (_beforeFolderMove == null)
+ HookBeforeFolderMove(true);
+ _beforeFolderMove += value;
+ }
+ remove
+ {
+ _beforeFolderMove -= value;
+ if (_beforeFolderMove == null)
+ HookBeforeFolderMove(false);
+ }
+ }
+
+ private void HookBeforeFolderMove(bool hook)
+ {
+ if (hook)
+ _item.BeforeFolderMove += HandleBeforeFolderMove;
+ else
+ _item.BeforeFolderMove -= HandleBeforeFolderMove;
+ }
+
+ private void HandleBeforeFolderMove(NSOutlook.MAPIFolder target, ref bool cancel)
+ {
+ try
+ {
+ if (_beforeFolderMove != null)
+ {
+ using (IFolder targetWrapped = Mapping.Wrap(target, false))
+ {
+ if (targetWrapped != null)
+ {
+ _beforeFolderMove(this, targetWrapped, ref cancel);
+ }
+ }
+ }
+ }
+ catch (System.Exception e)
+ {
+ Logger.Instance.Error(this, "Exception in HandleBeforeItemMove: {0}", e);
+ }
+ }
+
public void SetCustomIcon(IPicture icon)
{
_item.SetCustomIcon(((PictureWrapper)icon).RawItem as StdPicture);
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs
index 87bcb8a..f45cc70 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushFolder.cs
@@ -194,6 +194,7 @@ namespace Acacia.ZPush
foreach (var entry in remove)
{
Logger.Instance.Debug(this, "Removing subfolder {0}, {1}", Name, entry.Key);
+ _watcher.OnFolderRemoved(entry.Value);
_children.Remove(entry.Key);
entry.Value.Cleanup();
}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs
index 219b4a0..f681a44 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs
@@ -79,7 +79,7 @@ namespace Acacia.ZPush
///
/// Checks if this is a SyncId for a shared folders
///
- public bool IsShared { get { return _id.StartsWith("S"); } }
+ public bool IsShared { get { return _id.StartsWith("S") || _id.StartsWith("C") || _id.StartsWith("G"); } }
#region Standard overrides
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs
index 991116e..365a86d 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushWatcher.cs
@@ -212,10 +212,11 @@ namespace Acacia.ZPush
#region Folders
- private class FolderWatcher
+ public class FolderWatcher
{
- public FolderEventHandler Discovered;
- public FolderEventHandler Changed;
+ public FolderEventHandler Discovered { get; set; }
+ public FolderEventHandler Changed { get; set; }
+ public FolderEventHandler Removed { get; set; }
public void OnDiscovered(IFolder folder)
{
@@ -228,6 +229,28 @@ namespace Acacia.ZPush
if (Changed != null)
Changed(folder);
}
+
+ public void OnRemoved(IFolder folder)
+ {
+ if (Removed != null)
+ Removed(folder);
+ }
+
+ internal void Dispatch(ZPushFolder folder, EventKind kind)
+ {
+ switch (kind)
+ {
+ case EventKind.Discovered:
+ OnDiscovered(folder.Folder);
+ break;
+ case EventKind.Changed:
+ OnChanged(folder.Folder);
+ break;
+ case EventKind.Removed:
+ OnRemoved(folder.Folder);
+ break;
+ }
+ }
}
private readonly ConcurrentDictionary _folderWatchers = new ConcurrentDictionary();
@@ -239,10 +262,12 @@ namespace Acacia.ZPush
_rootFolder = new ZPushFolder(this, account.Account.Store.GetRootFolder());
}
- public void WatchFolder(FolderRegistration folder, FolderEventHandler handler, FolderEventHandler changedHandler = null)
+ public FolderWatcher WatchFolder(FolderRegistration folder, FolderEventHandler handler,
+ FolderEventHandler changedHandler = null,
+ FolderEventHandler removedHandler = null)
{
if (!DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED))
- return;
+ return null;
FolderWatcher watcher;
if (!_folderWatchers.TryGetValue(folder, out watcher))
@@ -254,15 +279,19 @@ namespace Acacia.ZPush
watcher.Discovered += handler;
if (changedHandler != null)
watcher.Changed += changedHandler;
+ if (removedHandler != null)
+ watcher.Removed += removedHandler;
// Check existing folders for events
- foreach(ZPushFolder existing in _allFolders)
+ foreach (ZPushFolder existing in _allFolders)
{
if (folder.IsApplicable(existing.Folder))
{
- DispatchFolderEvent(folder, watcher, existing, true);
+ DispatchFolderEvent(folder, watcher, existing, EventKind.Discovered);
}
}
+
+ return watcher;
}
private readonly List _allFolders = new List();
@@ -271,34 +300,44 @@ namespace Acacia.ZPush
{
Logger.Instance.Trace(this, "Folder discovered: {0}", folder);
_allFolders.Add(folder);
- DispatchFolderEvents(folder, true);
+ DispatchFolderEvents(folder, EventKind.Discovered);
}
internal void OnFolderChanged(ZPushFolder folder)
{
Logger.Instance.Trace(this, "Folder changed: {0}", folder);
- DispatchFolderEvents(folder, false);
+ DispatchFolderEvents(folder, EventKind.Changed);
}
- private void DispatchFolderEvents(ZPushFolder folder, bool isNew)
+ internal void OnFolderRemoved(ZPushFolder folder)
+ {
+ Logger.Instance.Trace(this, "Folder removed: {0}", folder);
+ DispatchFolderEvents(folder, EventKind.Removed);
+ }
+
+ internal enum EventKind
+ {
+ Discovered,
+ Changed,
+ Removed
+ }
+
+ private void DispatchFolderEvents(ZPushFolder folder, EventKind kind)
{
// See if anybody is interested
foreach (KeyValuePair entry in _folderWatchers)
{
if (entry.Key.IsApplicable(folder.Folder))
{
- DispatchFolderEvent(entry.Key, entry.Value, folder, isNew);
+ DispatchFolderEvent(entry.Key, entry.Value, folder, kind);
}
}
}
- private void DispatchFolderEvent(FolderRegistration reg, FolderWatcher watcher, ZPushFolder folder, bool isNew)
+ private void DispatchFolderEvent(FolderRegistration reg, FolderWatcher watcher, ZPushFolder folder, EventKind kind)
{
- Logger.Instance.Debug(this, "Folder event: {0}, {1}, {2}", folder, reg, isNew);
- if (isNew)
- watcher.OnDiscovered(folder.Folder);
- else
- watcher.OnChanged(folder.Folder);
+ Logger.Instance.Debug(this, "Folder event: {0}, {1}, {2}", folder, reg, kind);
+ watcher.Dispatch(folder, kind);
}
internal bool ShouldFolderBeWatched(ZPushFolder parent, IFolder child)