mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Cleaned up ZPushFolder, removed Folder subclass. It compiles, but will not run. Event handling code disabled for now.
This commit is contained in:
parent
297efe023b
commit
5842e90203
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Enums.cs
Normal file
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Enums.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Wrappers.cs
Normal file
17
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Wrappers.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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}";
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(NSOutlook.OlDefaultFolders defaultFolder in BLACKLISTED_MAIL_FOLDERS)
|
foreach(DefaultFolder defaultFolderId 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user