mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
[KOE-142] Added suppression and undo of local hierarchy changes to shared folders
This commit is contained in:
parent
212941132e
commit
c57c995b82
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -1075,6 +1075,24 @@ namespace Acacia.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Modifying shared folders locally is not supported. Please use the 'Shared Folders' dialog to modify these folders..
|
||||
/// </summary>
|
||||
internal static string SharedFolders_LocalFolder_Body {
|
||||
get {
|
||||
return ResourceManager.GetString("SharedFolders_LocalFolder_Body", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shared folders.
|
||||
/// </summary>
|
||||
internal static string SharedFolders_LocalFolder_Title {
|
||||
get {
|
||||
return ResourceManager.GetString("SharedFolders_LocalFolder_Title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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..
|
||||
/// </summary>
|
||||
|
@ -514,4 +514,10 @@
|
||||
<data name="SharedFolders_PrivateEvent_Title" xml:space="preserve">
|
||||
<value>Private event</value>
|
||||
</data>
|
||||
<data name="SharedFolders_LocalFolder_Body" xml:space="preserve">
|
||||
<value>Modifying shared folders locally is not supported. Please use the 'Shared Folders' dialog to modify these folders.</value>
|
||||
</data>
|
||||
<data name="SharedFolders_LocalFolder_Title" xml:space="preserve">
|
||||
<value>Shared folders</value>
|
||||
</data>
|
||||
</root>
|
@ -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
|
||||
|
||||
|
@ -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<IFolder>(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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ namespace Acacia.ZPush
|
||||
/// <summary>
|
||||
/// Checks if this is a SyncId for a shared folders
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
|
@ -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<FolderRegistration, FolderWatcher> _folderWatchers = new ConcurrentDictionary<FolderRegistration, FolderWatcher>();
|
||||
@ -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<ZPushFolder> _allFolders = new List<ZPushFolder>();
|
||||
@ -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<FolderRegistration, FolderWatcher> 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user