mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Reimplements folders and items events
This commit is contained in:
parent
cbf9207ff7
commit
dc12b73bbc
@ -286,7 +286,9 @@
|
||||
<Compile Include="Stubs\ICommandBars.cs" />
|
||||
<Compile Include="Stubs\IComWrapper.cs" />
|
||||
<Compile Include="Stubs\IExplorer.cs" />
|
||||
<Compile Include="Stubs\IFolders.cs" />
|
||||
<Compile Include="Stubs\IItemEvents.cs" />
|
||||
<Compile Include="Stubs\IItems.cs" />
|
||||
<Compile Include="Stubs\IOutlookWindow.cs" />
|
||||
<Compile Include="Stubs\IRecipient.cs" />
|
||||
<Compile Include="Stubs\IStores.cs" />
|
||||
@ -296,7 +298,9 @@
|
||||
<Compile Include="Stubs\OutlookWrappers\AddressEntryWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\CommandBarsWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\ExplorerWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\FoldersWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\ItemEventsWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\ItemsWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\OutlookItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\RecipientWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\StoresWrapper.cs" />
|
||||
|
@ -336,7 +336,7 @@ namespace Acacia.Features.GAB
|
||||
// Scan a few of the newest items, in case there is some junk in the ZPush folder
|
||||
// TODO: this shouldn't happen in production.
|
||||
int i = 0;
|
||||
foreach(IItem item in Folder.ItemsSorted("LastModificationTime", true))
|
||||
foreach(IItem item in Folder.Items.Sort("LastModificationTime", true))
|
||||
{
|
||||
using (item)
|
||||
{
|
||||
|
@ -35,9 +35,7 @@ namespace Acacia.Stubs
|
||||
|
||||
bool ShowAsOutlookAB { get; set; }
|
||||
|
||||
IEnumerable<IItem> Items { get; }
|
||||
|
||||
IEnumerable<IItem> ItemsSorted(string field, bool descending);
|
||||
IItems Items { get; }
|
||||
|
||||
IItem GetItemById(string id);
|
||||
|
||||
@ -58,7 +56,11 @@ namespace Acacia.Stubs
|
||||
|
||||
IEnumerable<FolderType> GetSubFolders<FolderType>()
|
||||
where FolderType : IFolder;
|
||||
IEnumerable<IFolder> GetSubFolders();
|
||||
|
||||
IFolders SubFolders
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
FolderType GetSubFolder<FolderType>(string name)
|
||||
where FolderType : IFolder;
|
||||
|
32
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolders.cs
Normal file
32
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolders.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Stubs
|
||||
{
|
||||
public delegate void IFolders_FolderEventHandler(IFolder folder);
|
||||
public delegate void IFolders_EventHandler();
|
||||
|
||||
public interface IFolders_Events : IDisposable
|
||||
{
|
||||
event IFolders_FolderEventHandler FolderAdd;
|
||||
event IFolders_FolderEventHandler FolderChange;
|
||||
event IFolders_EventHandler FolderRemove;
|
||||
}
|
||||
|
||||
public interface IFolders : IEnumerable<IFolder>
|
||||
{
|
||||
#region Events
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an events subscribption object.
|
||||
/// </summary>
|
||||
/// <returns>The events. The caller is responsible for disposing</returns>
|
||||
IFolders_Events GetEvents();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
34
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItems.cs
Normal file
34
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItems.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Acacia.Stubs
|
||||
{
|
||||
public delegate void IItems_ItemEventHandler(IItem item);
|
||||
|
||||
|
||||
public interface IItems_Events : IDisposable
|
||||
{
|
||||
event IItems_ItemEventHandler ItemAdd;
|
||||
event IItems_ItemEventHandler ItemChange;
|
||||
}
|
||||
|
||||
public interface IItems : IEnumerable<IItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Sorts the items.
|
||||
/// </summary>
|
||||
/// <param name="field"></param>
|
||||
/// <param name="descending"></param>
|
||||
/// <returns>The current collection, which will be sorted</returns>
|
||||
IItems Sort(string field, bool descending);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an events subscribption object.
|
||||
/// </summary>
|
||||
/// <returns>The events. The caller is responsible for disposing</returns>
|
||||
IItems_Events GetEvents();
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
abstract class ComWrapper<ItemType> : DisposableWrapper, IComWrapper
|
||||
{
|
||||
protected ItemType _item { get; private set; }
|
||||
protected readonly ItemType _item;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a wrapper.
|
||||
@ -49,7 +49,6 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
if (MustRelease)
|
||||
{
|
||||
ComRelease.Release(_item);
|
||||
_item = default(ItemType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,13 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DoRelease()
|
||||
{
|
||||
base.DoRelease();
|
||||
}
|
||||
|
||||
internal NSOutlook.Folder RawItem { get { return _item; } }
|
||||
|
||||
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||
{
|
||||
return _item.PropertyAccessor;
|
||||
@ -125,118 +132,15 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
|
||||
public ItemType ItemType { get { return (ItemType)(int)_item.DefaultItemType; } }
|
||||
|
||||
#region Enumeration
|
||||
|
||||
public class ItemsEnumerator<ItemType> : ComWrapper<NSOutlook.Items>, IEnumerator<ItemType>
|
||||
where ItemType : IItem
|
||||
{
|
||||
private IEnumerator _enum;
|
||||
private ItemType _last;
|
||||
|
||||
public ItemsEnumerator(NSOutlook.Folder folder, string field, bool descending) : base(folder.Items)
|
||||
{
|
||||
// TODO: can _items be released here already?
|
||||
if (field != null)
|
||||
{
|
||||
this._item.Sort("[" + field + "]", descending);
|
||||
}
|
||||
this._enum = _item.GetEnumerator();
|
||||
}
|
||||
|
||||
protected override void DoRelease()
|
||||
{
|
||||
CleanLast();
|
||||
if (_enum != null)
|
||||
{
|
||||
if (_enum is IDisposable)
|
||||
((IDisposable)_enum).Dispose();
|
||||
ComRelease.Release(_enum);
|
||||
_enum = null;
|
||||
}
|
||||
base.DoRelease();
|
||||
}
|
||||
|
||||
public ItemType Current
|
||||
public IItems Items
|
||||
{
|
||||
get
|
||||
{
|
||||
CleanLast();
|
||||
_last = Mapping.Wrap<ItemType>(_enum.Current);
|
||||
return _last;
|
||||
return new ItemsWrapper(this);
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanLast()
|
||||
{
|
||||
if (_last != null)
|
||||
{
|
||||
_last.Dispose();
|
||||
_last = default(ItemType);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
CleanLast();
|
||||
return _enum.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
CleanLast();
|
||||
_enum.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemsEnumerable<ItemType> : IEnumerable<ItemType>
|
||||
where ItemType : IItem
|
||||
{
|
||||
// Managed by the caller, not released here
|
||||
private readonly NSOutlook.Folder _folder;
|
||||
private readonly string _field;
|
||||
private readonly bool _descending;
|
||||
|
||||
public ItemsEnumerable(NSOutlook.Folder folder, string field, bool descending)
|
||||
{
|
||||
this._folder = folder;
|
||||
this._field = field;
|
||||
this._descending = descending;
|
||||
}
|
||||
|
||||
public IEnumerator<ItemType> GetEnumerator()
|
||||
{
|
||||
return new ItemsEnumerator<ItemType>(_folder, _field, _descending);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IItem> Items
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ItemsEnumerable<IItem>(_item, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IItem> ItemsSorted(string field, bool descending)
|
||||
{
|
||||
return new ItemsEnumerable<IItem>(_item, field, descending);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public IItem GetItemById(string entryId)
|
||||
{
|
||||
try
|
||||
@ -289,13 +193,16 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
// Don't release the items, the wrapper manages them
|
||||
foreach (NSOutlook.Folder folder in _item.Folders.RawEnum(false))
|
||||
{
|
||||
yield return WrapFolder<FolderType>(folder);
|
||||
yield return folder.Wrap<FolderType>();
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<IFolder> GetSubFolders()
|
||||
public IFolders SubFolders
|
||||
{
|
||||
return GetSubFolders<IFolder>();
|
||||
get
|
||||
{
|
||||
return new FoldersWrapper(this);
|
||||
}
|
||||
}
|
||||
|
||||
public FolderType GetSubFolder<FolderType>(string name)
|
||||
@ -319,7 +226,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
}
|
||||
if (sub == null)
|
||||
return default(FolderType);
|
||||
return WrapFolder<FolderType>(sub);
|
||||
return sub.Wrap<FolderType>();
|
||||
}
|
||||
|
||||
public FolderType CreateFolder<FolderType>(string name)
|
||||
@ -330,37 +237,19 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
NSOutlook.Folders folders = com.Add(_item.Folders);
|
||||
if (typeof(FolderType) == typeof(IFolder))
|
||||
{
|
||||
return WrapFolder<FolderType>(folders.Add(name));
|
||||
return folders.Add(name).Wrap<FolderType>();
|
||||
}
|
||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||
{
|
||||
NSOutlook.MAPIFolder newFolder = folders.Add(name, NSOutlook.OlDefaultFolders.olFolderContacts);
|
||||
newFolder.ShowAsOutlookAB = true;
|
||||
return WrapFolder<FolderType>(newFolder);
|
||||
return newFolder.Wrap<FolderType>();
|
||||
}
|
||||
else
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private FolderType WrapFolder<FolderType>(NSOutlook.MAPIFolder folder)
|
||||
where FolderType : IFolder
|
||||
{
|
||||
if (typeof(FolderType) == typeof(IFolder))
|
||||
{
|
||||
return (FolderType)(IFolder)new FolderWrapper(folder);
|
||||
}
|
||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||
{
|
||||
return (FolderType)(IFolder)new AddressBookWrapper(folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComRelease.Release(folder);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public IStorageItem GetStorageItem(string name)
|
||||
|
@ -0,0 +1,199 @@
|
||||
using Acacia.Utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
class FoldersWrapper : IFolders
|
||||
{
|
||||
// Managed by the caller, not released here
|
||||
private readonly FolderWrapper _folder;
|
||||
|
||||
public FoldersWrapper(FolderWrapper folder)
|
||||
{
|
||||
this._folder = folder;
|
||||
}
|
||||
|
||||
public IEnumerator<IFolder> GetEnumerator()
|
||||
{
|
||||
// Don't release the items, the wrapper manages them
|
||||
foreach (NSOutlook.Folder folder in _folder.RawItem.Folders.RawEnum(false))
|
||||
{
|
||||
yield return folder.Wrap<IFolder>();
|
||||
};
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
// Don't release the items, the wrapper manages them
|
||||
foreach (NSOutlook.Folder folder in _folder.RawItem.Folders.RawEnum(false))
|
||||
{
|
||||
yield return folder.Wrap<IFolder>();
|
||||
};
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
private class EventsWrapper : ComWrapper<NSOutlook.Folders>, IFolders_Events
|
||||
{
|
||||
public EventsWrapper(NSOutlook.Folders item) : base(item)
|
||||
{
|
||||
}
|
||||
|
||||
#region FolderAdd
|
||||
|
||||
private IFolders_FolderEventHandler _folderAdd;
|
||||
public event IFolders_FolderEventHandler FolderAdd
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_folderAdd == null)
|
||||
HookFolderAdd(true);
|
||||
_folderAdd += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_folderAdd -= value;
|
||||
if (_folderAdd == null)
|
||||
HookFolderAdd(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HookFolderAdd(bool hook)
|
||||
{
|
||||
if (hook)
|
||||
_item.FolderAdd += HandleFolderAdd;
|
||||
else
|
||||
_item.FolderAdd -= HandleFolderAdd;
|
||||
}
|
||||
|
||||
private void HandleFolderAdd(NSOutlook.MAPIFolder folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_folderAdd != null)
|
||||
{
|
||||
using (IFolder folderWrapped = Mapping.Wrap<IFolder>(folder, false))
|
||||
{
|
||||
if (folderWrapped != null)
|
||||
{
|
||||
_folderAdd(folderWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in HandleFolderAdd: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FolderChange
|
||||
|
||||
private IFolders_FolderEventHandler _folderChange;
|
||||
public event IFolders_FolderEventHandler FolderChange
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_folderChange == null)
|
||||
HookFolderChange(true);
|
||||
_folderChange += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_folderChange -= value;
|
||||
if (_folderChange == null)
|
||||
HookFolderChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HookFolderChange(bool hook)
|
||||
{
|
||||
if (hook)
|
||||
_item.FolderChange += HandleFolderChange;
|
||||
else
|
||||
_item.FolderChange -= HandleFolderChange;
|
||||
}
|
||||
|
||||
private void HandleFolderChange(NSOutlook.MAPIFolder folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_folderChange != null)
|
||||
{
|
||||
using (IFolder folderWrapped = Mapping.Wrap<IFolder>(folder, false))
|
||||
{
|
||||
if (folderWrapped != null)
|
||||
{
|
||||
_folderChange(folderWrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in HandleFolderChange: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FolderRemove
|
||||
|
||||
private IFolders_EventHandler _folderRemove;
|
||||
public event IFolders_EventHandler FolderRemove
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_folderRemove == null)
|
||||
HookFolderRemove(true);
|
||||
_folderRemove += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_folderRemove -= value;
|
||||
if (_folderRemove == null)
|
||||
HookFolderRemove(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HookFolderRemove(bool hook)
|
||||
{
|
||||
if (hook)
|
||||
_item.FolderRemove += HandleFolderRemove;
|
||||
else
|
||||
_item.FolderRemove -= HandleFolderRemove;
|
||||
}
|
||||
|
||||
private void HandleFolderRemove()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_folderRemove != null)
|
||||
{
|
||||
_folderRemove();
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in HandleFolderRemove: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public IFolders_Events GetEvents()
|
||||
{
|
||||
return new EventsWrapper(_folder.RawItem.Folders);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -0,0 +1,235 @@
|
||||
using Acacia.Utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
class ItemsWrapper : IItems
|
||||
{
|
||||
// Managed by the caller, not released here
|
||||
private readonly FolderWrapper _folder;
|
||||
private string _field;
|
||||
private bool _descending;
|
||||
|
||||
public ItemsWrapper(FolderWrapper folder)
|
||||
{
|
||||
this._folder = folder;
|
||||
}
|
||||
|
||||
public IItems Sort(string field, bool descending)
|
||||
{
|
||||
this._field = field;
|
||||
this._descending = descending;
|
||||
return this;
|
||||
}
|
||||
|
||||
private NSOutlook.Items GetItems()
|
||||
{
|
||||
return _folder.RawItem.Items;
|
||||
}
|
||||
|
||||
public IEnumerator<IItem> GetEnumerator()
|
||||
{
|
||||
return new ItemsEnumerator<IItem>(this, _field, _descending);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#region Enumeration
|
||||
|
||||
public class ItemsEnumerator<ItemType> : ComWrapper<NSOutlook.Items>, IEnumerator<ItemType>
|
||||
where ItemType : IItem
|
||||
{
|
||||
private IEnumerator _enum;
|
||||
private ItemType _last;
|
||||
|
||||
public ItemsEnumerator(ItemsWrapper items, string field, bool descending) : base(items.GetItems())
|
||||
{
|
||||
// TODO: can _items be released here already?
|
||||
if (field != null)
|
||||
{
|
||||
this._item.Sort("[" + field + "]", descending);
|
||||
}
|
||||
this._enum = _item.GetEnumerator();
|
||||
}
|
||||
|
||||
protected override void DoRelease()
|
||||
{
|
||||
CleanLast();
|
||||
if (_enum != null)
|
||||
{
|
||||
if (_enum is IDisposable)
|
||||
((IDisposable)_enum).Dispose();
|
||||
ComRelease.Release(_enum);
|
||||
_enum = null;
|
||||
}
|
||||
base.DoRelease();
|
||||
}
|
||||
|
||||
public ItemType Current
|
||||
{
|
||||
get
|
||||
{
|
||||
CleanLast();
|
||||
_last = Mapping.Wrap<ItemType>(_enum.Current);
|
||||
return _last;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
private void CleanLast()
|
||||
{
|
||||
if (_last != null)
|
||||
{
|
||||
_last.Dispose();
|
||||
_last = default(ItemType);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
CleanLast();
|
||||
return _enum.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
CleanLast();
|
||||
_enum.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
private class EventsWrapper : ComWrapper<NSOutlook.Items>, IItems_Events
|
||||
{
|
||||
public EventsWrapper(NSOutlook.Items item) : base(item)
|
||||
{
|
||||
}
|
||||
|
||||
#region ItemAdd
|
||||
|
||||
private IItems_ItemEventHandler _itemAdd;
|
||||
public event IItems_ItemEventHandler ItemAdd
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_itemAdd == null)
|
||||
HookItemAdd(true);
|
||||
_itemAdd += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_itemAdd -= value;
|
||||
if (_itemAdd == null)
|
||||
HookItemAdd(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HookItemAdd(bool hook)
|
||||
{
|
||||
if (hook)
|
||||
_item.ItemAdd += HandleItemAdd;
|
||||
else
|
||||
_item.ItemAdd -= HandleItemAdd;
|
||||
}
|
||||
|
||||
private void HandleItemAdd(object objItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_itemAdd != null)
|
||||
{
|
||||
using (IItem item = Mapping.Wrap<IItem>(objItem, false))
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
_itemAdd(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in HandleItemAdd: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ItemChange
|
||||
|
||||
private IItems_ItemEventHandler _itemChange;
|
||||
public event IItems_ItemEventHandler ItemChange
|
||||
{
|
||||
add
|
||||
{
|
||||
if (_itemChange == null)
|
||||
HookItemChange(true);
|
||||
_itemChange += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
_itemChange -= value;
|
||||
if (_itemChange == null)
|
||||
HookItemChange(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HookItemChange(bool hook)
|
||||
{
|
||||
if (hook)
|
||||
_item.ItemChange += HandleItemChange;
|
||||
else
|
||||
_item.ItemChange -= HandleItemChange;
|
||||
}
|
||||
|
||||
private void HandleItemChange(object objItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_itemChange != null)
|
||||
{
|
||||
using (IItem item = Mapping.Wrap<IItem>(objItem, false))
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
_itemChange(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Error(this, "Exception in HandleItemChange: {0}", e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public IItems_Events GetEvents()
|
||||
{
|
||||
return new EventsWrapper(GetItems());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Acacia.Stubs.OutlookWrappers;
|
||||
using Acacia.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -15,6 +16,25 @@ namespace Acacia.Stubs
|
||||
return Mapping.WrapOrDefault<IFolder>(obj);
|
||||
}
|
||||
|
||||
|
||||
public static FolderType Wrap<FolderType>(this NSOutlook.MAPIFolder folder)
|
||||
where FolderType : IFolder
|
||||
{
|
||||
if (typeof(FolderType) == typeof(IFolder))
|
||||
{
|
||||
return (FolderType)(IFolder)new FolderWrapper(folder);
|
||||
}
|
||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||
{
|
||||
return (FolderType)(IFolder)new AddressBookWrapper(folder);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComRelease.Release(folder);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static WrapType Wrap<WrapType>(this object o, bool mustRelease = true)
|
||||
where WrapType : IBase
|
||||
{
|
||||
|
@ -62,7 +62,6 @@ namespace Acacia.Utils
|
||||
ComRelease.Release(source);
|
||||
}
|
||||
|
||||
// TODO: check this
|
||||
public static IEnumerable RawEnum(this IEnumerable source, bool releaseItems = true)
|
||||
{
|
||||
foreach (object item in source)
|
||||
|
@ -27,10 +27,12 @@ namespace Acacia.ZPush
|
||||
{
|
||||
public class ZPushFolder : DisposableWrapper
|
||||
{
|
||||
private IFolder _folder;
|
||||
private ZPushFolder _parent;
|
||||
private readonly IFolder _folder;
|
||||
private readonly IItems_Events _items;
|
||||
private readonly IFolders_Events _subFolders;
|
||||
private readonly ZPushFolder _parent;
|
||||
private readonly ZPushWatcher _watcher;
|
||||
private List<ItemsWatcher> _itemsWatchers = new List<ItemsWatcher>();
|
||||
private readonly List<ItemsWatcher> _itemsWatchers = new List<ItemsWatcher>();
|
||||
|
||||
/// <summary>
|
||||
/// Children folders indexed by EntryID
|
||||
@ -50,6 +52,9 @@ namespace Acacia.ZPush
|
||||
this._parent = parent;
|
||||
this._watcher = watcher;
|
||||
this._folder = folder;
|
||||
// We need to keep links to these objects to keep getting events.
|
||||
this._items = folder.Items.GetEvents();
|
||||
this._subFolders = folder.SubFolders.GetEvents();
|
||||
folder.ZPush = this;
|
||||
}
|
||||
|
||||
@ -57,6 +62,13 @@ namespace Acacia.ZPush
|
||||
{
|
||||
Cleanup();
|
||||
_folder.Dispose();
|
||||
_items.Dispose();
|
||||
_subFolders.Dispose();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public IFolder Folder { get { return _folder; } }
|
||||
@ -71,7 +83,7 @@ namespace Acacia.ZPush
|
||||
_watcher.OnFolderDiscovered(this);
|
||||
|
||||
// Recurse the children
|
||||
foreach (IFolder subfolder in _folder.GetSubFolders())
|
||||
foreach (IFolder subfolder in _folder.SubFolders)
|
||||
{
|
||||
Tasks.Task(null, "WatchChild", () => WatchChild(subfolder));
|
||||
}
|
||||
@ -94,10 +106,10 @@ namespace Acacia.ZPush
|
||||
}
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void HookEvents(bool register)
|
||||
{
|
||||
// TODO
|
||||
/*
|
||||
if (register)
|
||||
{
|
||||
// Item events
|
||||
@ -119,8 +131,118 @@ namespace Acacia.ZPush
|
||||
_subFolders.FolderAdd -= SubFolders_FolderAdd;
|
||||
_subFolders.FolderRemove -= SubFolders_FolderRemove;
|
||||
_subFolders.FolderChange -= SubFolders_FolderChange;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void SubFolders_FolderAdd(IFolder folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Folder added in {0}: {1}", Name, folder.Name);
|
||||
WatchChild(folder);
|
||||
}
|
||||
catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderAdd: {0}: {1}", Name, e); }
|
||||
}
|
||||
|
||||
private void SubFolders_FolderRemove()
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Folder removed from {0}", Name);
|
||||
|
||||
// Helpfully, Outlook doesn't tell us which folder was removed. Could use the BeforeFolderMove event instead,
|
||||
// but that doesn't fire if a folder was removed on the server.
|
||||
// Hence, fetch all the remaining folder ids, and remove any folder that no longer exists.
|
||||
// TODO: move this logic into IFolders?
|
||||
HashSet<string> remaining = new HashSet<string>();
|
||||
foreach (IFolder child in _folder.SubFolders)
|
||||
{
|
||||
try
|
||||
{
|
||||
remaining.Add(child.EntryID);
|
||||
}
|
||||
catch (System.Exception e) { Logger.Instance.Warning(this, "Ignoring failed child: {0}", e); }
|
||||
}
|
||||
|
||||
// Find the folders that need to be removed. There should be only one, but with Outlook we can never be sure,
|
||||
// so compare all. We cannot modify the dictionary during iteration, so store entries to be removed in a
|
||||
// temporary list
|
||||
List<KeyValuePair<string, ZPushFolder>> remove = new List<KeyValuePair<string, ZPushFolder>>();
|
||||
foreach (var entry in _children)
|
||||
{
|
||||
if (!remaining.Contains(entry.Key))
|
||||
{
|
||||
remove.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Actually remove the folders
|
||||
foreach (var entry in remove)
|
||||
{
|
||||
Logger.Instance.Debug(this, "Removing subfolder {0}, {1}", Name, entry.Key);
|
||||
_children.Remove(entry.Key);
|
||||
entry.Value.Cleanup();
|
||||
}
|
||||
}
|
||||
catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderRemove: {0}: {1}", Name, e); }
|
||||
}
|
||||
|
||||
private void SubFolders_FolderChange(IFolder folder)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Folder changed in {0}: {1}", Name, folder.Name);
|
||||
ZPushFolder child;
|
||||
if (_children.TryGetValue(folder.EntryID, out child))
|
||||
{
|
||||
_watcher.OnFolderChanged(child);
|
||||
// TODO: release folder?
|
||||
}
|
||||
else
|
||||
{
|
||||
// On a clean profile, we sometimes get a change notification, but not an add notification
|
||||
// Create it now
|
||||
// This will send a discover notification if required, which is just as good as a change notification
|
||||
Logger.Instance.Debug(this, "Folder change on unreported folder in {0}: {1}, {2}, {3}", Name, folder.Name, folder.EntryID, folder.StoreDisplayName);
|
||||
WatchChild(folder);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderChange: {0}: {1}", Name, e); }
|
||||
}
|
||||
|
||||
private void Items_ItemAdd(IItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Trace(this, "New item {0}: {1}", Name, item.EntryID);
|
||||
foreach (ItemsWatcher watcher in _itemsWatchers)
|
||||
watcher.OnItemAdd(this, item);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Trace(this, "ItemAdd exception: {0}: {1}", Name, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void Items_ItemChange(IItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Instance.Trace(this, "Changed item {0}", Name);
|
||||
foreach (ItemsWatcher watcher in _itemsWatchers)
|
||||
watcher.OnItemChange(this, item);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Logger.Instance.Trace(this, "ItemChange exception: {0}: {1}", Name, e);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
|
@ -135,7 +135,7 @@ namespace Acacia.ZPush
|
||||
// Hide the folders that are not custom folders
|
||||
using (IFolder root = store.GetRootFolder())
|
||||
{
|
||||
foreach(IFolder sub in root.GetSubFolders())
|
||||
foreach(IFolder sub in root.SubFolders)
|
||||
{
|
||||
using (sub)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user