Cleaned up ZPushFolder, removed Folder subclass. It compiles, but will not run. Event handling code disabled for now.

This commit is contained in:
Patrick Simpson 2017-02-10 11:59:07 +01:00
parent 297efe023b
commit 5842e90203
29 changed files with 312 additions and 325 deletions

View File

@ -279,6 +279,7 @@
<Compile Include="Native\MAPI.cs" /> <Compile Include="Native\MAPI.cs" />
<Compile Include="Native\IOleWindow.cs" /> <Compile Include="Native\IOleWindow.cs" />
<Compile Include="OutlookConstants.cs" /> <Compile Include="OutlookConstants.cs" />
<Compile Include="Stubs\Enums.cs" />
<Compile Include="Stubs\IAddIn.cs" /> <Compile Include="Stubs\IAddIn.cs" />
<Compile Include="Stubs\IAddressEntry.cs" /> <Compile Include="Stubs\IAddressEntry.cs" />
<Compile Include="Stubs\ICommandBars.cs" /> <Compile Include="Stubs\ICommandBars.cs" />
@ -292,12 +293,14 @@
<Compile Include="Stubs\OutlookWrappers\ExplorerWrapper.cs" /> <Compile Include="Stubs\OutlookWrappers\ExplorerWrapper.cs" />
<Compile Include="Stubs\OutlookWrappers\OutlookItemWrapper.cs" /> <Compile Include="Stubs\OutlookWrappers\OutlookItemWrapper.cs" />
<Compile Include="Stubs\OutlookWrappers\RecipientWrapper.cs" /> <Compile Include="Stubs\OutlookWrappers\RecipientWrapper.cs" />
<Compile Include="Stubs\Wrappers.cs" />
<Compile Include="UI\Outlook\OutlookImageList.cs" /> <Compile Include="UI\Outlook\OutlookImageList.cs" />
<Compile Include="UI\Outlook\RibbonToggleButton.cs" /> <Compile Include="UI\Outlook\RibbonToggleButton.cs" />
<Compile Include="UI\Outlook\RibbonButton.cs" /> <Compile Include="UI\Outlook\RibbonButton.cs" />
<Compile Include="UI\Outlook\CommandElement.cs" /> <Compile Include="UI\Outlook\CommandElement.cs" />
<Compile Include="UI\Outlook\MenuItem.cs" /> <Compile Include="UI\Outlook\MenuItem.cs" />
<Compile Include="UI\Outlook\Types.cs" /> <Compile Include="UI\Outlook\Types.cs" />
<Compile Include="Utils\DisposableWrapper.cs" />
<Compile Include="Utils\ImageUtils.cs" /> <Compile Include="Utils\ImageUtils.cs" />
<Compile Include="Utils\RegistryUtil.cs" /> <Compile Include="Utils\RegistryUtil.cs" />
<Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" /> <Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" />
@ -323,7 +326,6 @@
<Compile Include="ZPush\Connect\ZPushRequestEncoder.cs" /> <Compile Include="ZPush\Connect\ZPushRequestEncoder.cs" />
<Compile Include="ZPush\Connect\Soap\SoapRequestEncoder.cs" /> <Compile Include="ZPush\Connect\Soap\SoapRequestEncoder.cs" />
<Compile Include="ZPush\Connect\Soap\SoapRequest.cs" /> <Compile Include="ZPush\Connect\Soap\SoapRequest.cs" />
<Compile Include="Stubs\ItemType.cs" />
<Compile Include="Stubs\OutlookWrappers\ComWrapper.cs" /> <Compile Include="Stubs\OutlookWrappers\ComWrapper.cs" />
<Compile Include="UI\FeatureSettings.cs"> <Compile Include="UI\FeatureSettings.cs">
<SubType>UserControl</SubType> <SubType>UserControl</SubType>

View File

@ -251,7 +251,7 @@ namespace Acacia.Features.GAB
if (_processing == 0) if (_processing == 0)
{ {
// Check parent folder is a GAB contacts folder // Check parent folder is a GAB contacts folder
if (_gabFolders.Contains(item.ParentEntryId) && IsGABItem(item)) if (_gabFolders.Contains(item.ParentEntryID) && IsGABItem(item))
{ {
DoSuppressEvent(findInspector ? item : null, ref cancel); DoSuppressEvent(findInspector ? item : null, ref cancel);
} }
@ -434,7 +434,7 @@ namespace Acacia.Features.GAB
gab.AttrHidden = false; gab.AttrHidden = false;
// Update admin // Update admin
_gabFolders.Add(gab.EntryId); _gabFolders.Add(gab.EntryID);
GABInfo gabInfo = GABInfo.Get(gab, domainName); GABInfo gabInfo = GABInfo.Get(gab, domainName);
gabInfo.Store(gab); gabInfo.Store(gab);
@ -548,7 +548,7 @@ namespace Acacia.Features.GAB
GABInfo info = GetGABContactsFolderInfo(subfolder); GABInfo info = GetGABContactsFolderInfo(subfolder);
if (info != null && !_domains.Contains(info.Domain)) if (info != null && !_domains.Contains(info.Domain))
{ {
Logger.Instance.Info(this, "Unused GAB folder: {0} - {1}", subfolder.EntryId, subfolder.Name); Logger.Instance.Info(this, "Unused GAB folder: {0} - {1}", subfolder.EntryID, subfolder.Name);
try try
{ {
deletedSomething = true; deletedSomething = true;

View File

@ -205,7 +205,7 @@ namespace Acacia.Features.GAB
// TODO: make type-checking iterator? // TODO: make type-checking iterator?
if (item is IZPushItem) if (item is IZPushItem)
{ {
string entryId = item.EntryId; string entryId = item.EntryID;
Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject); Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject);
if (_feature.ProcessItems2) if (_feature.ProcessItems2)
{ {
@ -613,7 +613,7 @@ namespace Acacia.Features.GAB
{ {
using (IItem item = FindItemById(memberId)) using (IItem item = FindItemById(memberId))
{ {
Logger.Instance.Debug(this, "Finding member {0} of {1}: {2}", memberId, id, item?.EntryId); Logger.Instance.Debug(this, "Finding member {0} of {1}: {2}", memberId, id, item?.EntryID);
if (item != null) if (item != null)
AddGroupMember(group, item); AddGroupMember(group, item);
} }
@ -670,7 +670,7 @@ namespace Acacia.Features.GAB
{ {
using (IItem groupItem = FindItemById(memberOf)) using (IItem groupItem = FindItemById(memberOf))
{ {
Logger.Instance.Debug(this, "Finding group {0} for {1}: {2}", memberOf, id, groupItem?.EntryId); Logger.Instance.Debug(this, "Finding group {0} for {1}: {2}", memberOf, id, groupItem?.EntryID);
if (groupItem is IDistributionList) if (groupItem is IDistributionList)
{ {
AddGroupMember((IDistributionList)groupItem, item); AddGroupMember((IDistributionList)groupItem, item);

View File

@ -92,7 +92,7 @@ namespace Acacia.Features.Notes
{ {
// Only patch if on a ZPush server that supports notes. Store the folder as entryId, there have been some // Only patch if on a ZPush server that supports notes. Store the folder as entryId, there have been some
// issues with the folder object being disposed in the past // issues with the folder object being disposed in the past
string folderId = folder.EntryId; string folderId = folder.EntryID;
ZPushAccount zpush = Watcher.Accounts.GetAccount(folder); ZPushAccount zpush = Watcher.Accounts.GetAccount(folder);
if (zpush != null) if (zpush != null)
{ {
@ -219,7 +219,7 @@ namespace Acacia.Features.Notes
{ {
if ((int)item.GetProperty(OutlookConstants.PR_ICON_INDEX) != 771) if ((int)item.GetProperty(OutlookConstants.PR_ICON_INDEX) != 771)
{ {
Logger.Instance.Trace(this, "Patching item: {0}", item.EntryId); Logger.Instance.Trace(this, "Patching item: {0}", item.EntryID);
// Patch standard properties // Patch standard properties
item.SetProperties( item.SetProperties(

View File

@ -106,9 +106,9 @@ namespace Acacia.Features.SecondaryContacts
Logger.Instance.Debug(this, "Patched secondary contacts folder: {0}", strippedName); Logger.Instance.Debug(this, "Patched secondary contacts folder: {0}", strippedName);
// Register and show a warning, if not already done. // Register and show a warning, if not already done.
// Note that patching may be done multiple times. // Note that patching may be done multiple times.
if (!_warnedFolders.Contains(folder.EntryId)) if (!_warnedFolders.Contains(folder.EntryID))
{ {
_warnedFolders.Add(folder.EntryId); _warnedFolders.Add(folder.EntryID);
if (MessageBox.Show(StringUtil.GetResourceString("SecondaryContactsPatched_Body", strippedName), if (MessageBox.Show(StringUtil.GetResourceString("SecondaryContactsPatched_Body", strippedName),
StringUtil.GetResourceString("SecondaryContactsPatched_Title"), StringUtil.GetResourceString("SecondaryContactsPatched_Title"),
@ -121,7 +121,7 @@ namespace Acacia.Features.SecondaryContacts
} }
} }
// If _warnedFolders does not contain the folder (and it's hidden), this means Outlook was restarted. // If _warnedFolders does not contain the folder (and it's hidden), this means Outlook was restarted.
else if (!_warnedFolders.Contains(folder.EntryId)) else if (!_warnedFolders.Contains(folder.EntryID))
{ {
// Stage 2 // Stage 2

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acacia.Stubs
{
// Replacement for olItemType
public enum ItemType
{
MailItem = 0,
AppointmentItem = 1,
ContactItem = 2,
TaskItem = 3,
JournalItem = 4,
NoteItem = 5,
PostItem = 6,
DistributionListItem = 7,
MobileItemSMS = 11,
MobileItemMMS = 12
}
// Replacement for olDefaultFolders
public enum DefaultFolder
{
DeletedItems = 3,
Outbox = 4,
SentMail = 5,
Inbox = 6,
Calendar = 9,
Contacts = 10,
Journal = 11,
Notes = 12,
Tasks = 13,
Drafts = 16,
FoldersAllPublicFolders = 18,
Conflicts = 19,
SyncIssues = 20,
LocalFailures = 21,
ServerFailures = 22,
Junk = 23,
RssFeeds = 25,
ToDo = 28,
ManagedEmail = 29,
SuggestedContacts = 30
}
}

View File

@ -36,11 +36,16 @@ namespace Acacia.Stubs
#region Ids and hierarchy #region Ids and hierarchy
string EntryId { get; } string EntryID { get; }
IFolder Parent { get; } IFolder Parent { get; }
string ParentEntryId { get; } string ParentEntryID { get; }
/// <summary>
/// Returns the store. The owner is responsible for disposing.
/// TODO: make method to make disposing clear
/// </summary>
IStore Store { get; } IStore Store { get; }
/// <summary> /// <summary>
/// Quick accessor to Store.Id, to prevent allocating a wrapper for it. /// Quick accessor to Store.Id, to prevent allocating a wrapper for it.
/// </summary> /// </summary>

View File

@ -41,6 +41,10 @@ namespace Acacia.Stubs
IItem GetItemById(string id); IItem GetItemById(string id);
string FullFolderPath { get; }
ItemType DefaultItemType { get; }
#endregion #endregion
#region Searching #region Searching

View File

@ -29,6 +29,17 @@ namespace Acacia.Stubs
/// </summary> /// </summary>
/// <returns>The root folder. The caller is responsible for disposing.</returns> /// <returns>The root folder. The caller is responsible for disposing.</returns>
IFolder GetRootFolder(); IFolder GetRootFolder();
/// <summary>
/// Returns a default folder.
/// </summary>
/// <returns>The default folder. The caller is responsible for disposing.</returns>
IFolder GetDefaultFolder(DefaultFolder folder);
/// <summary>
/// Returns GetDefaultFolder.EntryID, for simplified memory manaement
/// </summary>
string GetDefaultFolderId(DefaultFolder folder);
IItem GetItemFromID(string id); IItem GetItemFromID(string id);
string DisplayName { get; } string DisplayName { get; }
string StoreID { get; } string StoreID { get; }

View File

@ -1,38 +0,0 @@
/// Copyright 2016 Kopano b.v.
///
/// This program is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License, version 3,
/// as published by the Free Software Foundation.
///
/// This program is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
/// GNU Affero General Public License for more details.
///
/// You should have received a copy of the GNU Affero General Public License
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
///
/// Consult LICENSE file for details
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acacia.Stubs
{
public enum ItemType
{
MailItem = 0,
AppointmentItem = 1,
ContactItem = 2,
TaskItem = 3,
JournalItem = 4,
NoteItem = 5,
PostItem = 6,
DistributionListItem = 7,
MobileItemSMS = 11,
MobileItemMMS = 12
}
}

View File

@ -228,7 +228,7 @@ namespace Acacia.Stubs.OutlookWrappers
// And fetch it and wrap // And fetch it and wrap
NSOutlook.Stores stores = com.Add(session.Stores); NSOutlook.Stores stores = com.Add(session.Stores);
return StoreWrapper.Wrap(stores[stores.Count]); return Mapping.Wrap(stores[stores.Count]);
} }
} }
@ -242,7 +242,7 @@ namespace Acacia.Stubs.OutlookWrappers
NSOutlook.Stores stores = com.Add(session.Stores); NSOutlook.Stores stores = com.Add(session.Stores);
foreach (NSOutlook.Store store in stores) foreach (NSOutlook.Store store in stores)
{ {
yield return StoreWrapper.Wrap(store); yield return Mapping.Wrap(store);
} }
} }
} }

View File

@ -93,7 +93,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -104,7 +104,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -123,7 +123,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -25,50 +25,7 @@ using System.Threading.Tasks;
namespace Acacia.Stubs.OutlookWrappers namespace Acacia.Stubs.OutlookWrappers
{ {
abstract class RawComWrapper : IComWrapper abstract class ComWrapper<ItemType> : DisposableWrapper, IComWrapper
{
protected RawComWrapper()
{
Interlocked.Increment(ref Statistics.CreatedWrappers);
this._createdTrace = new System.Diagnostics.StackTrace();
MustRelease = true;
}
~RawComWrapper()
{
Interlocked.Increment(ref Statistics.DeletedWrappers);
if (!_isDisposed)
{
Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
// Dispose, but don't count auto disposals, so the stats show it.
DoRelease();
}
}
private bool _isDisposed;
private readonly System.Diagnostics.StackTrace _createdTrace;
virtual public void Dispose()
{
if (!_isDisposed)
{
Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace());
_isDisposed = true;
Interlocked.Increment(ref Statistics.DisposedWrappers);
DoRelease();
}
}
public bool MustRelease
{
get;
set;
}
abstract protected void DoRelease();
}
abstract class ComWrapper<ItemType> : RawComWrapper
{ {
protected ItemType _item { get; private set; } protected ItemType _item { get; private set; }
@ -78,6 +35,13 @@ namespace Acacia.Stubs.OutlookWrappers
protected ComWrapper(ItemType item) protected ComWrapper(ItemType item)
{ {
this._item = item; this._item = item;
MustRelease = true;
}
public bool MustRelease
{
get;
set;
} }
override protected void DoRelease() override protected void DoRelease()

View File

@ -218,7 +218,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -229,7 +229,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -248,7 +248,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -160,7 +160,7 @@ namespace Acacia.Stubs.OutlookWrappers
{ {
List<byte> id = new List<byte>(); List<byte> id = new List<byte>();
id.AddRange(PREFIX_MEMBER_ID); id.AddRange(PREFIX_MEMBER_ID);
id.AddRange(StringUtil.HexToBytes(member.EntryId)); id.AddRange(StringUtil.HexToBytes(member.EntryID));
return id.ToArray(); return id.ToArray();
} }
@ -234,7 +234,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -245,7 +245,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -264,7 +264,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -39,6 +39,8 @@ namespace Acacia.Stubs.OutlookWrappers
return _item.PropertyAccessor; return _item.PropertyAccessor;
} }
public string FullFolderPath { get { return _item.FullFolderPath; } }
public IFolder Parent public IFolder Parent
{ {
get get
@ -48,7 +50,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -96,9 +98,10 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IStore Store { get { return Mapping.Wrap(_item.Store); } }
public IStore Store { get { return StoreWrapper.Wrap(_item.Store); } }
public string StoreId public string StoreId
{ {
get get
@ -460,5 +463,9 @@ namespace Acacia.Stubs.OutlookWrappers
#endregion #endregion
public ItemType DefaultItemType
{
get { return (ItemType)(int)_item.DefaultItemType; }
}
} }
} }

View File

@ -127,7 +127,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -138,7 +138,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -157,7 +157,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -80,11 +80,23 @@ namespace Acacia.Stubs.OutlookWrappers
public static IRecipient Wrap(NSOutlook.Recipient r, bool mustRelease = true) public static IRecipient Wrap(NSOutlook.Recipient r, bool mustRelease = true)
{ {
if (r == null)
return null;
RecipientWrapper wrapped = new RecipientWrapper(r); RecipientWrapper wrapped = new RecipientWrapper(r);
wrapped.MustRelease = mustRelease; wrapped.MustRelease = mustRelease;
return wrapped; return wrapped;
} }
// TODO: extension methods for this
public static IStore Wrap(NSOutlook.Store obj, bool mustRelease = true)
{
if (obj == null)
return null;
StoreWrapper wrapped = new StoreWrapper(obj);
wrapped.MustRelease = mustRelease;
return wrapped;
}
// TODO: are these not the same now? Differ only on wrong type? // TODO: are these not the same now? Differ only on wrong type?
public static Type WrapOrDefault<Type>(object o, bool mustRelease = true) public static Type WrapOrDefault<Type>(object o, bool mustRelease = true)
where Type : IBase where Type : IBase

View File

@ -74,7 +74,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -85,7 +85,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -104,7 +104,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -72,7 +72,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -83,7 +83,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -102,7 +102,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -26,12 +26,7 @@ namespace Acacia.Stubs.OutlookWrappers
{ {
class StoreWrapper : ComWrapper<NSOutlook.Store>, IStore class StoreWrapper : ComWrapper<NSOutlook.Store>, IStore
{ {
internal static IStore Wrap(NSOutlook.Store store) internal StoreWrapper(NSOutlook.Store store) : base(store)
{
return store == null ? null : new StoreWrapper(store);
}
private StoreWrapper(NSOutlook.Store store) : base(store)
{ {
} }
@ -41,6 +36,25 @@ namespace Acacia.Stubs.OutlookWrappers
return new FolderWrapper((NSOutlook.Folder)_item.GetRootFolder()); return new FolderWrapper((NSOutlook.Folder)_item.GetRootFolder());
} }
public IFolder GetDefaultFolder(DefaultFolder folder)
{
// FolderWrapper manages the returned Folder
return new FolderWrapper((NSOutlook.Folder)_item.GetDefaultFolder((NSOutlook.OlDefaultFolders)(int)folder));
}
public string GetDefaultFolderId(DefaultFolder folder)
{
NSOutlook.MAPIFolder mapiFolder = _item.GetDefaultFolder((NSOutlook.OlDefaultFolders)(int)folder);
try
{
return mapiFolder.EntryID;
}
finally
{
ComRelease.Release(mapiFolder);
}
}
public IItem GetItemFromID(string id) public IItem GetItemFromID(string id)
{ {
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
@ -79,6 +93,5 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
} }
} }
} }

View File

@ -72,7 +72,7 @@ namespace Acacia.Stubs.OutlookWrappers
#region IBase implementation #region IBase implementation
public string EntryId { get { return _item.EntryID; } } public string EntryID { get { return _item.EntryID; } }
public IFolder Parent public IFolder Parent
{ {
@ -83,7 +83,7 @@ namespace Acacia.Stubs.OutlookWrappers
} }
} }
public string ParentEntryId public string ParentEntryID
{ {
get get
{ {
@ -102,7 +102,7 @@ namespace Acacia.Stubs.OutlookWrappers
using (ComRelease com = new ComRelease()) using (ComRelease com = new ComRelease())
{ {
NSOutlook.Folder parent = com.Add(_item.Parent); NSOutlook.Folder parent = com.Add(_item.Parent);
return StoreWrapper.Wrap(parent?.Store); return Mapping.Wrap(parent?.Store);
} }
} }
} }

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NSOutlook = Microsoft.Office.Interop.Outlook;
namespace Acacia.Stubs
{
public static class Wrappers
{
public static IFolder Wrap(this NSOutlook.MAPIFolder obj)
{
throw new NotImplementedException(); // TODO
}
}
}

View File

@ -0,0 +1,47 @@
using Acacia.Features.DebugSupport;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Acacia.Utils
{
abstract public class DisposableWrapper : IDisposable
{
protected DisposableWrapper()
{
Interlocked.Increment(ref Statistics.CreatedWrappers);
this._createdTrace = new System.Diagnostics.StackTrace();
}
~DisposableWrapper()
{
Interlocked.Increment(ref Statistics.DeletedWrappers);
if (!_isDisposed)
{
Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
// Dispose, but don't count auto disposals, so the stats show it.
DoRelease();
}
}
private bool _isDisposed;
private readonly System.Diagnostics.StackTrace _createdTrace;
virtual public void Dispose()
{
if (!_isDisposed)
{
Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace());
_isDisposed = true;
Interlocked.Increment(ref Statistics.DisposedWrappers);
DoRelease();
}
}
abstract protected void DoRelease();
}
}

View File

@ -252,7 +252,7 @@ namespace Acacia.ZPush.Connect
} }
} }
private class Request : RawComWrapper private class Request : DisposableWrapper
{ {
private const string ACTIVESYNC_URL = "https://{0}/Microsoft-Server-ActiveSync?DeviceId={1}&Cmd={2}&User={3}&DeviceType={4}"; private const string ACTIVESYNC_URL = "https://{0}/Microsoft-Server-ActiveSync?DeviceId={1}&Cmd={2}&User={3}&DeviceType={4}";

View File

@ -15,6 +15,7 @@
/// Consult LICENSE file for details /// Consult LICENSE file for details
using Acacia.Stubs; using Acacia.Stubs;
using Acacia.Stubs.OutlookWrappers;
using Acacia.Utils; using Acacia.Utils;
using Acacia.ZPush.Connect; using Acacia.ZPush.Connect;
using Microsoft.Win32; using Microsoft.Win32;
@ -32,21 +33,20 @@ using NSOutlook = Microsoft.Office.Interop.Outlook;
namespace Acacia.ZPush namespace Acacia.ZPush
{ {
[TypeConverter(typeof(ExpandableObjectConverter))] [TypeConverter(typeof(ExpandableObjectConverter))]
public class ZPushAccount : LogContext public class ZPushAccount : DisposableWrapper, LogContext
{ {
#region Miscellaneous #region Miscellaneous
private readonly string _regPath; private readonly string _regPath;
// TODO: this should probably be wrapped. Make ZPushAccount ComWrapper? private readonly IStore _store;
private readonly NSOutlook.Store _store;
/// <summary> /// <summary>
/// Constructor. /// Constructor.
/// </summary> /// </summary>
/// <param name="regPath">They registry key containing the account settings.</param> /// <param name="regPath">They registry key containing the account settings.</param>
/// <param name="store">The store this account represents.</param> /// <param name="store">The store this account represents. The new object takes ownership</param>
internal ZPushAccount(string regPath, NSOutlook.Store store) internal ZPushAccount(string regPath, IStore store)
{ {
this._regPath = regPath; this._regPath = regPath;
this._store = store; this._store = store;
@ -55,6 +55,11 @@ namespace Acacia.ZPush
SmtpAddress = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EMAIL, null); SmtpAddress = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EMAIL, null);
} }
protected override void DoRelease()
{
_store.Dispose();
}
[Browsable(false)] [Browsable(false)]
public string LogContextId public string LogContextId
{ {
@ -83,8 +88,7 @@ namespace Acacia.ZPush
#region Properties #region Properties
[Browsable(false)] [Browsable(false)]
// TODO: remove this public IStore Store
public NSOutlook.Store Store
{ {
get get
{ {
@ -229,7 +233,7 @@ namespace Acacia.ZPush
public void LinkedGABFolder(IFolder folder) public void LinkedGABFolder(IFolder folder)
{ {
GABFolderLinked = folder.EntryId; GABFolderLinked = folder.EntryID;
} }
internal void OnConfirmationResponse(ZPushConnection.Response response) internal void OnConfirmationResponse(ZPushConnection.Response response)

View File

@ -15,6 +15,7 @@
/// Consult LICENSE file for details /// Consult LICENSE file for details
using Acacia.Stubs; using Acacia.Stubs;
using Acacia.Stubs.OutlookWrappers;
using Acacia.Utils; using Acacia.Utils;
using Microsoft.Win32; using Microsoft.Win32;
using System; using System;
@ -238,36 +239,41 @@ namespace Acacia.ZPush
/// </summary> /// </summary>
private void StoreAdded(NSOutlook.Store s) private void StoreAdded(NSOutlook.Store s)
{ {
IStore store = null;
try try
{ {
using (ComRelease com = new ComRelease()) // Accessing the store object causes random crashes, simply iterate to find new stores
Logger.Instance.Trace(this, "StoreAdded: {0}", s.StoreID);
foreach (NSOutlook.Store rawStore in _session.Stores.RawEnum(false))
{ {
Logger.Instance.Trace(this, "StoreAdded: {0}", s.StoreID); if (!_accountsByStoreId.ContainsKey(rawStore.StoreID))
foreach (NSOutlook.Store store in com.Add(com.Add(_app.Session).Stores))
{ {
if (!_accountsByStoreId.ContainsKey(store.StoreID)) Logger.Instance.Trace(this, "New store: {0}", rawStore.DisplayName);
store = Mapping.Wrap(rawStore);
ZPushAccount zpush = TryCreateFromRegistry(store);
if (zpush == null)
{ {
Logger.Instance.Trace(this, "New store: {0}", store.DisplayName); // Add it to the cache so it is not evaluated again.
ZPushAccount zpush = TryCreateFromRegistry(store); _accountsByStoreId.Add(store.StoreID, null);
if (zpush == null) Logger.Instance.Trace(this, "Not a ZPush store: {0}", store.DisplayName);
{ store.Dispose();
// Add it to the cache so it is not evaluated again. }
_accountsByStoreId.Add(store.StoreID, null); else
Logger.Instance.Trace(this, "Not a ZPush store: {0}", store.DisplayName); {
} Logger.Instance.Trace(this, "New ZPush store: {0}: {1}", store.DisplayName, zpush);
else _watcher.OnAccountDiscovered(zpush, false);
{ // zpush has taken ownership
Logger.Instance.Trace(this, "New ZPush store: {0}: {1}", store.DisplayName, zpush);
_watcher.OnAccountDiscovered(zpush, false);
}
} }
else ComRelease.Release(store);
} }
else ComRelease.Release(rawStore);
} }
} }
catch(System.Exception e) catch(System.Exception e)
{ {
Logger.Instance.Error(this, "StoreAdded Exception: {0}", e); Logger.Instance.Error(this, "StoreAdded Exception: {0}", e);
if (store != null)
store.Dispose();
} }
} }
@ -287,6 +293,7 @@ namespace Acacia.ZPush
/// <param name="account">The account. The caller is responsible for releasing this.</param> /// <param name="account">The account. The caller is responsible for releasing this.</param>
/// <returns>The associated ZPushAccount</returns> /// <returns>The associated ZPushAccount</returns>
/// <exception cref="Exception">If the registry key cannot be found</exception> /// <exception cref="Exception">If the registry key cannot be found</exception>
// TODO: check management of account
private ZPushAccount CreateFromRegistry(NSOutlook.Account account) private ZPushAccount CreateFromRegistry(NSOutlook.Account account)
{ {
// TODO: check that caller releases account everywhere // TODO: check that caller releases account everywhere
@ -300,10 +307,10 @@ namespace Acacia.ZPush
string storeId = ZPushAccount.GetStoreId(baseKey.Name); string storeId = ZPushAccount.GetStoreId(baseKey.Name);
// Find the store // Find the store
NSOutlook.Store store = _app.Session.GetStoreFromID(storeId); NSOutlook.Store store = _session.GetStoreFromID(storeId);
// Done, create and register // Done, create and register
ZPushAccount zpush = new ZPushAccount(baseKey.Name, store); ZPushAccount zpush = new ZPushAccount(baseKey.Name, Mapping.Wrap(store));
Register(zpush); Register(zpush);
return zpush; return zpush;
} }
@ -312,9 +319,9 @@ namespace Acacia.ZPush
/// <summary> /// <summary>
/// Creates the ZPushAccount for the store, from the registry. /// Creates the ZPushAccount for the store, from the registry.
/// </summary> /// </summary>
/// <param name="store">The store</param> /// <param name="store">The store. Ownership is transferred to the ZPushAccount. If the account is not created, the store is NOT disposed</param>
/// <returns>The ZPushAccount, or null if no account is associated with the store</returns> /// <returns>The ZPushAccount, or null if no account is associated with the store</returns>
private ZPushAccount TryCreateFromRegistry(NSOutlook.Store store) private ZPushAccount TryCreateFromRegistry(IStore store)
{ {
using (RegistryKey baseKey = FindRegistryKey(store)) using (RegistryKey baseKey = FindRegistryKey(store))
{ {
@ -363,7 +370,7 @@ namespace Acacia.ZPush
/// Finds the registry key for the account associated with the store. /// Finds the registry key for the account associated with the store.
/// </summary> /// </summary>
/// <returns>The registry key, or null if it cannot be found</returns> /// <returns>The registry key, or null if it cannot be found</returns>
private RegistryKey FindRegistryKey(NSOutlook.Store store) private RegistryKey FindRegistryKey(IStore store)
{ {
// Find the registry key by store id // Find the registry key by store id
using (RegistryKey key = OpenBaseKey()) using (RegistryKey key = OpenBaseKey())

View File

@ -22,15 +22,12 @@ using System.Linq;
using Acacia.Utils; using Acacia.Utils;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using NSOutlook = Microsoft.Office.Interop.Outlook;
namespace Acacia.ZPush namespace Acacia.ZPush
{ {
// TODO: make this contain Folder instead of inheriting, then FolderWrapper needn't be public public class ZPushFolder : DisposableWrapper
public class ZPushFolder : FolderWrapper
{ {
private readonly NSOutlook.Items _items; private IFolder _folder;
private readonly NSOutlook.Folders _subFolders;
private ZPushFolder _parent; private ZPushFolder _parent;
private readonly ZPushWatcher _watcher; private readonly ZPushWatcher _watcher;
private List<ItemsWatcher> _itemsWatchers = new List<ItemsWatcher>(); private List<ItemsWatcher> _itemsWatchers = new List<ItemsWatcher>();
@ -40,24 +37,29 @@ namespace Acacia.ZPush
/// </summary> /// </summary>
protected readonly Dictionary<string, ZPushFolder> _children = new Dictionary<string, ZPushFolder>(); protected readonly Dictionary<string, ZPushFolder> _children = new Dictionary<string, ZPushFolder>();
internal ZPushFolder(ZPushWatcher watcher, NSOutlook.Folder folder) internal ZPushFolder(ZPushWatcher watcher, IFolder folder)
: :
this(watcher, null, folder) this(watcher, null, folder)
{ {
Initialise(); Initialise();
} }
private ZPushFolder(ZPushWatcher watcher, ZPushFolder parent, NSOutlook.Folder folder) private ZPushFolder(ZPushWatcher watcher, ZPushFolder parent, IFolder folder)
:
base(folder)
{ {
Logger.Instance.Trace(this, "Watching folder: {1}: {0}", folder.EntryID, folder.Name); Logger.Instance.Trace(this, "Watching folder: {1}: {0}", folder.EntryID, folder.Name);
this._parent = parent; this._parent = parent;
this._watcher = watcher; this._watcher = watcher;
this._items = folder.Items; this._folder = folder;
this._subFolders = folder.Folders;
} }
protected override void DoRelease()
{
_folder.Dispose();
}
public IFolder Folder { get; }
public string Name { get { return _folder.Name; } }
private void Initialise() private void Initialise()
{ {
// Register the events // Register the events
@ -67,20 +69,21 @@ namespace Acacia.ZPush
_watcher.OnFolderDiscovered(this); _watcher.OnFolderDiscovered(this);
// Recurse the children // Recurse the children
foreach (NSOutlook.Folder subfolder in this._subFolders) foreach (IFolder subfolder in _folder.GetSubFolders())
{ {
Tasks.Task(null, "WatchChild", () => WatchChild(subfolder)); Tasks.Task(null, "WatchChild", () => WatchChild(subfolder));
} }
} }
public override void Dispose() // TODO
/*public override void Dispose()
{ {
Logger.Instance.Trace(this, "Disposing folder: {0}", _item.Name); Logger.Instance.Trace(this, "Disposing folder: {0}", _item.Name);
Cleanup(); Cleanup();
base.Dispose(); base.Dispose();
ComRelease.Release(_items); ComRelease.Release(_items);
ComRelease.Release(_subFolders); ComRelease.Release(_subFolders);
} }*/
internal ItemsWatcher ItemsWatcher() internal ItemsWatcher ItemsWatcher()
{ {
@ -92,7 +95,7 @@ namespace Acacia.ZPush
public void ReportExistingItems<TypedItem>(TypedItemEventHandler<TypedItem> handler) public void ReportExistingItems<TypedItem>(TypedItemEventHandler<TypedItem> handler)
where TypedItem : IItem where TypedItem : IItem
{ {
foreach(IItem item in Items) foreach(IItem item in _folder.Items)
{ {
if (item is TypedItem) if (item is TypedItem)
handler((TypedItem)item); handler((TypedItem)item);
@ -101,6 +104,8 @@ namespace Acacia.ZPush
private void HookEvents(bool register) private void HookEvents(bool register)
{ {
// TODO
/*
if (register) if (register)
{ {
// Item events // Item events
@ -122,12 +127,12 @@ namespace Acacia.ZPush
_subFolders.FolderAdd -= SubFolders_FolderAdd; _subFolders.FolderAdd -= SubFolders_FolderAdd;
_subFolders.FolderRemove -= SubFolders_FolderRemove; _subFolders.FolderRemove -= SubFolders_FolderRemove;
_subFolders.FolderChange -= SubFolders_FolderChange; _subFolders.FolderChange -= SubFolders_FolderChange;
} }*/
} }
private void Cleanup() private void Cleanup()
{ {
Logger.Instance.Trace(this, "Unwatching folder: {0}", _item.Name); Logger.Instance.Trace(this, "Unwatching folder: {0}", _folder.Name);
// The events need to be unhooked explicitly, otherwise we get double notifications if a folder is moved // The events need to be unhooked explicitly, otherwise we get double notifications if a folder is moved
HookEvents(false); HookEvents(false);
foreach (ZPushFolder child in _children.Values) foreach (ZPushFolder child in _children.Values)
@ -141,7 +146,7 @@ namespace Acacia.ZPush
/// Watches the child folder. /// Watches the child folder.
/// </summary> /// </summary>
/// <param name="child">The child folder. Ownership will be taken.</param> /// <param name="child">The child folder. Ownership will be taken.</param>
private void WatchChild(NSOutlook.Folder child) private void WatchChild(IFolder child)
{ {
if (!_children.ContainsKey(child.EntryID)) if (!_children.ContainsKey(child.EntryID))
{ {
@ -165,124 +170,5 @@ namespace Acacia.ZPush
// Release the folder if not used // Release the folder if not used
ComRelease.Release(child); ComRelease.Release(child);
} }
#region Event handlers
private void SubFolders_FolderAdd(NSOutlook.MAPIFolder folder)
{
try
{
Logger.Instance.Debug(this, "Folder added in {0}: {1}", this._item.Name, folder.Name);
WatchChild((NSOutlook.Folder)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}", this._item.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.
HashSet<string> remaining = new HashSet<string>();
foreach (NSOutlook.Folder child in _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}", this._item.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(NSOutlook.MAPIFolder folder)
{
try
{
Logger.Instance.Debug(this, "Folder changed in {0}: {1}", this._item.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}", this._item.Name, folder.Name, folder.EntryID, folder.Store.DisplayName);
WatchChild((NSOutlook.Folder)folder);
}
}
catch (System.Exception e) { Logger.Instance.Error(this, "Exception in SubFolders_FolderChange: {0}: {1}", Name, e); }
}
private void Items_ItemAdd(object oItem)
{
try
{
using (IItem item = Mapping.Wrap<IItem>(oItem))
{
if (item != null)
{
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(object oItem)
{
try
{
using (IItem item = Mapping.Wrap<IItem>(oItem))
{
if (item != null)
{
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
} }
} }

View File

@ -37,6 +37,7 @@ namespace Acacia.ZPush
/// </summary> /// </summary>
public class ZPushWatcher public class ZPushWatcher
{ {
// TODO: remove
private readonly NSOutlook.Application _app; private readonly NSOutlook.Application _app;
public readonly ZPushAccounts Accounts; public readonly ZPushAccounts Accounts;
public readonly ZPushSync Sync; public readonly ZPushSync Sync;
@ -277,7 +278,7 @@ namespace Acacia.ZPush
private void HandleFolderWatchers(ZPushAccount account) private void HandleFolderWatchers(ZPushAccount account)
{ {
// We need to keep the object alive to keep receiving events // We need to keep the object alive to keep receiving events
_rootFolder = new ZPushFolder(this, (NSOutlook.Folder)account.Store.GetRootFolder()); _rootFolder = new ZPushFolder(this, account.Store.GetRootFolder());
} }
public void WatchFolder(FolderRegistration folder, FolderEventHandler handler, FolderEventHandler changedHandler = null) public void WatchFolder(FolderRegistration folder, FolderEventHandler handler, FolderEventHandler changedHandler = null)
@ -299,7 +300,7 @@ namespace Acacia.ZPush
// Check existing folders for events // Check existing folders for events
foreach(ZPushFolder existing in _allFolders) foreach(ZPushFolder existing in _allFolders)
{ {
if (folder.IsApplicable(existing)) if (folder.IsApplicable(existing.Folder))
{ {
DispatchFolderEvent(folder, watcher, existing, true); DispatchFolderEvent(folder, watcher, existing, true);
} }
@ -326,7 +327,7 @@ namespace Acacia.ZPush
// See if anybody is interested // See if anybody is interested
foreach (KeyValuePair<FolderRegistration, FolderWatcher> entry in _folderWatchers) foreach (KeyValuePair<FolderRegistration, FolderWatcher> entry in _folderWatchers)
{ {
if (entry.Key.IsApplicable(folder)) if (entry.Key.IsApplicable(folder.Folder))
{ {
DispatchFolderEvent(entry.Key, entry.Value, folder, isNew); DispatchFolderEvent(entry.Key, entry.Value, folder, isNew);
} }
@ -337,17 +338,17 @@ namespace Acacia.ZPush
{ {
Logger.Instance.Debug(this, "Folder event: {0}, {1}, {2}", folder, reg, isNew); Logger.Instance.Debug(this, "Folder event: {0}, {1}, {2}", folder, reg, isNew);
if (isNew) if (isNew)
watcher.OnDiscovered(folder); watcher.OnDiscovered(folder.Folder);
else else
watcher.OnChanged(folder); watcher.OnChanged(folder.Folder);
} }
internal bool ShouldFolderBeWatched(ZPushFolder parent, NSOutlook.Folder child) internal bool ShouldFolderBeWatched(ZPushFolder parent, IFolder child)
{ {
if (parent.IsAtDepth(0)) if (parent.Folder.IsAtDepth(0))
{ {
// Special mail folders cause issues, they are disallowed // Special mail folders cause issues, they are disallowed
if (child.DefaultItemType != NSOutlook.OlItemType.olMailItem) if (child.DefaultItemType != ItemType.MailItem)
return true; return true;
return !IsBlackListedMailFolder(child); return !IsBlackListedMailFolder(child);
@ -355,30 +356,27 @@ namespace Acacia.ZPush
return true; return true;
} }
private static readonly NSOutlook.OlDefaultFolders[] BLACKLISTED_MAIL_FOLDERS = private static readonly DefaultFolder[] BLACKLISTED_MAIL_FOLDERS =
{ {
NSOutlook.OlDefaultFolders.olFolderOutbox, DefaultFolder.Outbox,
NSOutlook.OlDefaultFolders.olFolderDrafts, DefaultFolder.Drafts,
NSOutlook.OlDefaultFolders.olFolderConflicts, DefaultFolder.Conflicts,
NSOutlook.OlDefaultFolders.olFolderSyncIssues, DefaultFolder.SyncIssues,
NSOutlook.OlDefaultFolders.olFolderRssFeeds, DefaultFolder.RssFeeds,
NSOutlook.OlDefaultFolders.olFolderManagedEmail DefaultFolder.ManagedEmail
}; };
private static bool IsBlackListedMailFolder(NSOutlook.Folder folder) private static bool IsBlackListedMailFolder(IFolder folder)
{ {
string entryId = folder.EntryID; string entryId = folder.EntryID;
using (ComRelease com = new ComRelease())
using (IStore store = folder.Store)
{ {
NSOutlook.Store store = com.Add(folder.Store); foreach(DefaultFolder defaultFolderId in BLACKLISTED_MAIL_FOLDERS)
foreach(NSOutlook.OlDefaultFolders defaultFolder in BLACKLISTED_MAIL_FOLDERS)
{ {
try if (entryId == store.GetDefaultFolderId(defaultFolderId))
{ return true;
if (entryId == com.Add(store.GetDefaultFolder(defaultFolder)).EntryID)
return true;
}
catch (System.Exception) { }
} }
} }
return false; return false;