mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Merge branch 'master' into release_1_2
# Conflicts: # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddressEntry.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IComWrapper.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ICommandBars.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ComWrapper.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/ExplorerWrapper.cs # src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/RecipientWrapper.cs # src/AcaciaZPushPlugin/OutlookRestarter/Properties/AssemblyInfo.cs # translations/KOE.pot # translations/en.po
This commit is contained in:
commit
c55091bcc7
24
CONTRIBUTING.md
Normal file
24
CONTRIBUTING.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# How to contribute to the Kopano OL Extension
|
||||||
|
|
||||||
|
If you have found an issue and want to report an issue, either reach out to us
|
||||||
|
in our [forum](http://forum.kopano.com), or, if you have a subscription, open
|
||||||
|
up a [support case](https://kopano.com/support/).
|
||||||
|
|
||||||
|
To provide changesets,
|
||||||
|
|
||||||
|
- Clone the repository from https://stash.kopano.io/ or
|
||||||
|
https://github.com/Kopano-mirror/ .
|
||||||
|
- Commit and [sign your work](
|
||||||
|
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v4.10-rc4#n416)
|
||||||
|
(```git commit -s```).
|
||||||
|
- Upload commits to a git store of your choosing, or export the series as a
|
||||||
|
patchset using [git format-patch](https://git-scm.com/docs/git-format-patch).
|
||||||
|
- Send the patch(es) or git link to
|
||||||
|
[contributing@kopano.io](mailto:contributing@kopano.io) and we will consider
|
||||||
|
the submission.
|
||||||
|
|
||||||
|
## Additional notes
|
||||||
|
|
||||||
|
- Please only work on one issue per commit.
|
||||||
|
- Before implementing a new feature, get in contact with us, so we can
|
||||||
|
determine the impact.
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Kopano OL Extension
|
||||||
|
We live in a world where it is a commodity to work with apps or web interfaces – just have a look at the big amounts of HTML5-apps on your tablets and smartphones. However, there are situations in which a rich application is needed. Think about working offline during a five hour flight or deeper integrations like writing series of letters in your Office suite.
|
||||||
|
|
||||||
|
This is exactly why we developed the Kopano Outlook Extension (KOE). If you are on the road a lot and thus without an internet connection, or if you rely heavily on specialised plugins in Outlook, then the Kopano OL Extension might just be the thing for you.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
In-depth documentation, such as administration and user manuals, about our
|
||||||
|
products be be found on our [Documentation Portal](https://documentation.kopano.io/). Additionally a [Knowledge Base](https://kb.kopano.io/) is available for quick start guides, handy code
|
||||||
|
snippets, and troubleshooting help.
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
The main development of Kopano Core takes place in a [private Bitbucket
|
||||||
|
instance](https://stash.kopano.io/projects/KOE/repos/kopano_ol_extension_source/)
|
||||||
|
with development tickets organised in [Jira](https://jira.kopano.io/projects/KC/). Please see
|
||||||
|
[CONTRIBUTING.md](CONTRIBUTING.md) for steps on how to contribute patches.
|
||||||
|
|
||||||
|
# Downloading compiled packages
|
||||||
|
Compiled packages are only available to subscription
|
||||||
|
holders from the the [Kopano Portal](https://portal.kopano.com/) and a
|
||||||
|
[package repository](
|
||||||
|
https://download.kopano.io/supported/olextension:/).
|
||||||
|
|
||||||
|
# Support
|
||||||
|
Community Support is available through the [Kopano Forum](
|
||||||
|
https://forum.kopano.io/) and through the #Kopano channel on Freenode IRC
|
||||||
|
network. [Additional support options](https://kopano.com/support/) are
|
||||||
|
available for subscription holders.
|
@ -1,12 +1,14 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.25123.0
|
VisualStudioVersion = 14.0.25420.1
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AcaciaZPushPlugin", "AcaciaZPushPlugin\AcaciaZPushPlugin.csproj", "{1A7427A5-F814-4B07-98B2-C67D758B65D6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AcaciaZPushPlugin", "AcaciaZPushPlugin\AcaciaZPushPlugin.csproj", "{1A7427A5-F814-4B07-98B2-C67D758B65D6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDebugger", "PluginDebugger\PluginDebugger.csproj", "{9258AD17-0A25-4669-A95C-93EC70882551}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDebugger", "PluginDebugger\PluginDebugger.csproj", "{9258AD17-0A25-4669-A95C-93EC70882551}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookRestarter", "OutlookRestarter\OutlookRestarter.csproj", "{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -41,6 +43,18 @@ Global
|
|||||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.Build.0 = Release|Any CPU
|
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.ActiveCfg = Release|Any CPU
|
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.Build.0 = Release|Any CPU
|
{9258AD17-0A25-4669-A95C-93EC70882551}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -125,7 +125,7 @@
|
|||||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||||
<DefineConstants>VSTO40</DefineConstants>
|
<DefineConstants>VSTO40</DefineConstants>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<!--
|
<!--
|
||||||
@ -241,6 +241,7 @@
|
|||||||
<Compile Include="Controls\KUITask.cs" />
|
<Compile Include="Controls\KUITask.cs" />
|
||||||
<Compile Include="Controls\KUIUtil.cs" />
|
<Compile Include="Controls\KUIUtil.cs" />
|
||||||
<Compile Include="DebugOptions.cs" />
|
<Compile Include="DebugOptions.cs" />
|
||||||
|
<Compile Include="Features\SecondaryContacts\FeatureSecondaryContacts.cs" />
|
||||||
<Compile Include="Features\DebugSupport\AboutDialog.cs">
|
<Compile Include="Features\DebugSupport\AboutDialog.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
@ -275,13 +276,44 @@
|
|||||||
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
||||||
<Compile Include="GlobalOptions.cs" />
|
<Compile Include="GlobalOptions.cs" />
|
||||||
<Compile Include="Logging.cs" />
|
<Compile Include="Logging.cs" />
|
||||||
|
<Compile Include="Native\MAPI.cs" />
|
||||||
|
<Compile Include="Native\IOleWindow.cs" />
|
||||||
<Compile Include="OutlookConstants.cs" />
|
<Compile Include="OutlookConstants.cs" />
|
||||||
|
<Compile Include="Stubs\Enums.cs" />
|
||||||
|
<Compile Include="Stubs\IAccount.cs" />
|
||||||
|
<Compile Include="Stubs\IAddIn.cs" />
|
||||||
|
<Compile Include="Stubs\IAddressEntry.cs" />
|
||||||
|
<Compile Include="Stubs\ICommandBars.cs" />
|
||||||
|
<Compile Include="Stubs\IComWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\IExplorer.cs" />
|
||||||
|
<Compile Include="Stubs\IFolders.cs" />
|
||||||
|
<Compile Include="Stubs\IItemEvents.cs" />
|
||||||
|
<Compile Include="Stubs\IItems.cs" />
|
||||||
|
<Compile Include="Stubs\IOutlookWindow.cs" />
|
||||||
|
<Compile Include="Stubs\IRecipient.cs" />
|
||||||
|
<Compile Include="Stubs\IStores.cs" />
|
||||||
|
<Compile Include="Stubs\ISyncObject.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\AccountWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\AddInWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\AddressEntryWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\CommandBarsWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\ExplorerWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\FoldersWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\ItemEventsWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\ItemsWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\OutlookItemWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\RecipientWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\StoresWrapper.cs" />
|
||||||
|
<Compile Include="Stubs\OutlookWrappers\SyncObjectWrapper.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\RegistryUtil.cs" />
|
<Compile Include="Utils\RegistryUtil.cs" />
|
||||||
<Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" />
|
<Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" />
|
||||||
<Compile Include="ZPush\API\SharedFolders\SharedFolder.cs" />
|
<Compile Include="ZPush\API\SharedFolders\SharedFolder.cs" />
|
||||||
@ -306,8 +338,7 @@
|
|||||||
<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\DisposableWrapper.cs" />
|
|
||||||
<Compile Include="UI\FeatureSettings.cs">
|
<Compile Include="UI\FeatureSettings.cs">
|
||||||
<SubType>UserControl</SubType>
|
<SubType>UserControl</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
@ -393,7 +424,6 @@
|
|||||||
<Compile Include="Stubs\INoteItem.cs" />
|
<Compile Include="Stubs\INoteItem.cs" />
|
||||||
<Compile Include="Stubs\ISearch.cs" />
|
<Compile Include="Stubs\ISearch.cs" />
|
||||||
<Compile Include="Stubs\IStorageItem.cs" />
|
<Compile Include="Stubs\IStorageItem.cs" />
|
||||||
<Compile Include="Stubs\IUserProperty.cs" />
|
|
||||||
<Compile Include="Stubs\IZPushItem.cs" />
|
<Compile Include="Stubs\IZPushItem.cs" />
|
||||||
<Compile Include="Stubs\OutlookWrappers\AddressBookWrapper.cs" />
|
<Compile Include="Stubs\OutlookWrappers\AddressBookWrapper.cs" />
|
||||||
<Compile Include="Stubs\OutlookWrappers\DistributionListWrapper.cs" />
|
<Compile Include="Stubs\OutlookWrappers\DistributionListWrapper.cs" />
|
||||||
@ -408,7 +438,6 @@
|
|||||||
<Compile Include="Stubs\OutlookWrappers\SearchWrapper.cs" />
|
<Compile Include="Stubs\OutlookWrappers\SearchWrapper.cs" />
|
||||||
<Compile Include="Stubs\OutlookWrappers\StorageItemWrapper.cs" />
|
<Compile Include="Stubs\OutlookWrappers\StorageItemWrapper.cs" />
|
||||||
<Compile Include="Stubs\OutlookWrappers\StoreWrapper.cs" />
|
<Compile Include="Stubs\OutlookWrappers\StoreWrapper.cs" />
|
||||||
<Compile Include="Stubs\OutlookWrappers\UserPropertyWrapper.cs" />
|
|
||||||
<Compile Include="Stubs\IStore.cs" />
|
<Compile Include="Stubs\IStore.cs" />
|
||||||
<Compile Include="UI\ProgressDialog.cs">
|
<Compile Include="UI\ProgressDialog.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
|
Binary file not shown.
@ -71,6 +71,7 @@ namespace Acacia
|
|||||||
|
|
||||||
public const string ZPUSH_HEADER_GAB_NAME = "X-Push-GAB-Name";
|
public const string ZPUSH_HEADER_GAB_NAME = "X-Push-GAB-Name";
|
||||||
public const string ZPUSH_HEADER_CAPABILITIES = "X-Push-Capabilities";
|
public const string ZPUSH_HEADER_CAPABILITIES = "X-Push-Capabilities";
|
||||||
|
public const string ZPUSH_HEADER_CLIENT_CAPABILITIES = "X-Push-Plugin-Capabilities";
|
||||||
public const string ZPUSH_HEADER_PLUGIN = "X-Push-Plugin";
|
public const string ZPUSH_HEADER_PLUGIN = "X-Push-Plugin";
|
||||||
public const string ZPUSH_HEADER_VERSION = "X-Z-Push-Version";
|
public const string ZPUSH_HEADER_VERSION = "X-Z-Push-Version";
|
||||||
|
|
||||||
|
@ -68,19 +68,25 @@ namespace Acacia
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class EnumOption<EnumType> : Option<EnumType>
|
public class EnumOption<EnumType> : Option<EnumType>
|
||||||
|
where EnumType : struct
|
||||||
{
|
{
|
||||||
|
private readonly EnumType? _defaultValue;
|
||||||
|
|
||||||
private EnumType DefaultValue
|
private EnumType DefaultValue
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
if (_defaultValue.HasValue)
|
||||||
|
return (EnumType)_defaultValue;
|
||||||
return (EnumType)typeof(EnumType).GetEnumValues().GetValue(0);
|
return (EnumType)typeof(EnumType).GetEnumValues().GetValue(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnumOption(string token)
|
public EnumOption(string token, EnumType? defaultValue = null)
|
||||||
:
|
:
|
||||||
base(token)
|
base(token)
|
||||||
{
|
{
|
||||||
|
this._defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string GetToken(EnumType value)
|
public override string GetToken(EnumType value)
|
||||||
|
@ -47,6 +47,76 @@ namespace Acacia.Features.DebugSupport
|
|||||||
Properties.Refresh();
|
Properties.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DebugCycleInfo
|
||||||
|
{
|
||||||
|
private int cycleIndex = 0;
|
||||||
|
private int cycleCount;
|
||||||
|
private Timer timer = new Timer();
|
||||||
|
private GAB.FeatureGAB gab;
|
||||||
|
private int zeroCount = 1000;
|
||||||
|
|
||||||
|
public DebugCycleInfo(DebugDialog dlg, GAB.FeatureGAB gab, int count)
|
||||||
|
{
|
||||||
|
this.cycleCount = count;
|
||||||
|
this.gab = gab;
|
||||||
|
timer.Interval = 1000;
|
||||||
|
timer.Tick += (a, b) =>
|
||||||
|
{
|
||||||
|
dlg.Text = string.Format("Cycle {0} of {1}", cycleIndex + 1, cycleCount);
|
||||||
|
dlg.GarbageCollect();
|
||||||
|
|
||||||
|
if (((DebugInfo)dlg.Properties.SelectedObject).ActiveTasks == 0)
|
||||||
|
{
|
||||||
|
// Make sure the value is stable at zero
|
||||||
|
++zeroCount;
|
||||||
|
if (zeroCount >= 3)
|
||||||
|
{
|
||||||
|
zeroCount = 0;
|
||||||
|
Logger.Instance.Debug(this, "CYCLER");
|
||||||
|
++cycleIndex;
|
||||||
|
|
||||||
|
if (cycleIndex >= cycleCount)
|
||||||
|
{
|
||||||
|
timer.Stop();
|
||||||
|
dlg.Hide();
|
||||||
|
ThisAddIn.Instance.Quit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugCycle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DebugCycle()
|
||||||
|
{
|
||||||
|
Tasks.Task(gab, "DebugCycle", () =>
|
||||||
|
{
|
||||||
|
gab.FullResync();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private DebugCycleInfo cycle;
|
||||||
|
|
||||||
|
internal void DebugCycle(int count)
|
||||||
|
{
|
||||||
|
GAB.FeatureGAB gab = ThisAddIn.Instance.GetFeature<GAB.FeatureGAB>();
|
||||||
|
if (gab != null)
|
||||||
|
{
|
||||||
|
cycle = new DebugCycleInfo(this, gab, count);
|
||||||
|
cycle.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Logging
|
#region Logging
|
||||||
|
|
||||||
private const string INDENT = "+";
|
private const string INDENT = "+";
|
||||||
@ -89,11 +159,12 @@ namespace Acacia.Features.DebugSupport
|
|||||||
|
|
||||||
private void buttonGC_Click(object sender, EventArgs e)
|
private void buttonGC_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
GC.Collect();
|
GarbageCollect();
|
||||||
GC.WaitForPendingFinalizers();
|
}
|
||||||
GC.Collect();
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
|
|
||||||
|
private void GarbageCollect()
|
||||||
|
{
|
||||||
|
Util.GarbageCollect();
|
||||||
UpdateFields();
|
UpdateFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ namespace Acacia.Features.DebugSupport
|
|||||||
{
|
{
|
||||||
Version,
|
Version,
|
||||||
Memory,
|
Memory,
|
||||||
|
Tasks,
|
||||||
Wrappers,
|
Wrappers,
|
||||||
Misc,
|
Misc,
|
||||||
System,
|
System,
|
||||||
@ -101,9 +102,9 @@ namespace Acacia.Features.DebugSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add Add-ins
|
// Add Add-ins
|
||||||
foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns)
|
foreach (KeyValuePair<string,string> addin in ThisAddIn.Instance.COMAddIns)
|
||||||
{
|
{
|
||||||
PropertyDescriptor p = new CustomPropertyDescriptor<string, DebugInfo>(addin.ProgId, DebugCategory.AddIns, addin.Description);
|
PropertyDescriptor p = new CustomPropertyDescriptor<string, DebugInfo>(addin.Key, DebugCategory.AddIns, addin.Value);
|
||||||
properties.Add(p);
|
properties.Add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,6 +134,25 @@ namespace Acacia.Features.DebugSupport
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Tasks
|
||||||
|
|
||||||
|
[DebugCategory(DebugCategory.Tasks)]
|
||||||
|
public string Threading
|
||||||
|
{
|
||||||
|
get { return Tasks.Executor.Name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebugCategory(DebugCategory.Tasks)]
|
||||||
|
public long ActiveTasks { get { return Statistics.StartedTasks - Statistics.FinishedTasks; } }
|
||||||
|
|
||||||
|
[DebugCategory(DebugCategory.Tasks)]
|
||||||
|
public long StartedTasks { get { return Statistics.StartedTasks; } }
|
||||||
|
|
||||||
|
[DebugCategory(DebugCategory.Tasks)]
|
||||||
|
public long FinishedTasks { get { return Statistics.FinishedTasks; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Wrappers
|
#region Wrappers
|
||||||
|
|
||||||
[DebugCategory(DebugCategory.Wrappers)]
|
[DebugCategory(DebugCategory.Wrappers)]
|
||||||
@ -163,12 +183,6 @@ namespace Acacia.Features.DebugSupport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[DebugCategory(DebugCategory.Misc)]
|
|
||||||
public string Threading
|
|
||||||
{
|
|
||||||
get { return Tasks.Executor.Name; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebugCategory(DebugCategory.Misc)]
|
[DebugCategory(DebugCategory.Misc)]
|
||||||
public bool ZPushSync
|
public bool ZPushSync
|
||||||
{
|
{
|
||||||
@ -234,7 +248,7 @@ namespace Acacia.Features.DebugSupport
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return ThisAddIn.Instance.Application.Version;
|
return ThisAddIn.Instance.Version;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Acacia.Features.ReplyFlags;
|
using Acacia.Features.ReplyFlags;
|
||||||
@ -47,6 +45,14 @@ namespace Acacia.Features.DebugSupport
|
|||||||
RegisterButton(this, "Settings", false, ShowSettings);
|
RegisterButton(this, "Settings", false, ShowSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void AfterStartup()
|
||||||
|
{
|
||||||
|
/*DebugDialog dd = new DebugDialog();
|
||||||
|
dd.Show();
|
||||||
|
dd.DebugCycle(5);*/
|
||||||
|
}
|
||||||
|
|
||||||
#region About dialog
|
#region About dialog
|
||||||
|
|
||||||
public void ShowAbout()
|
public void ShowAbout()
|
||||||
|
@ -25,6 +25,9 @@ namespace Acacia.Features.DebugSupport
|
|||||||
{
|
{
|
||||||
public static class Statistics
|
public static class Statistics
|
||||||
{
|
{
|
||||||
|
public static long StartedTasks;
|
||||||
|
public static long FinishedTasks;
|
||||||
|
|
||||||
public static long CreatedWrappers;
|
public static long CreatedWrappers;
|
||||||
public static long DeletedWrappers;
|
public static long DeletedWrappers;
|
||||||
public static long DisposedWrappers;
|
public static long DisposedWrappers;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -58,9 +57,9 @@ namespace Acacia.Features
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Microsoft.Office.Interop.Outlook.Application App
|
virtual public void GetCapabilities(ZPushCapabilities caps)
|
||||||
{
|
{
|
||||||
get { return ThisAddIn.Instance.Application; }
|
caps.Add(Name.ToLower());
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Debug options
|
#region Debug options
|
||||||
@ -195,14 +194,11 @@ namespace Acacia.Features
|
|||||||
|
|
||||||
#region Event helpers
|
#region Event helpers
|
||||||
|
|
||||||
private static MailEvents _mailEvents;
|
|
||||||
protected static MailEvents MailEvents
|
protected static MailEvents MailEvents
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_mailEvents == null)
|
return ThisAddIn.Instance.MailEvents;
|
||||||
_mailEvents = new MailEvents(App);
|
|
||||||
return _mailEvents;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +223,11 @@ namespace Acacia.Features
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void AfterStartup()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Z-Push channels
|
#region Z-Push channels
|
||||||
|
@ -33,6 +33,7 @@ namespace Acacia.Features
|
|||||||
typeof(FreeBusy.FeatureFreeBusy),
|
typeof(FreeBusy.FeatureFreeBusy),
|
||||||
typeof(GAB.FeatureGAB),
|
typeof(GAB.FeatureGAB),
|
||||||
typeof(Notes.FeatureNotes),
|
typeof(Notes.FeatureNotes),
|
||||||
|
typeof(SecondaryContacts.FeatureSecondaryContacts),
|
||||||
typeof(SendAs.FeatureSendAs),
|
typeof(SendAs.FeatureSendAs),
|
||||||
typeof(DebugSupport.FeatureDebugSupport)
|
typeof(DebugSupport.FeatureDebugSupport)
|
||||||
};
|
};
|
||||||
|
@ -103,7 +103,7 @@ namespace Acacia.Features.FreeBusy
|
|||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
RegistryUtil.SetConfigValue(Name, REG_DEFAULTACCOUNT, value == null ? "" : value.SmtpAddress, RegistryValueKind.String);
|
RegistryUtil.SetConfigValue(Name, REG_DEFAULTACCOUNT, value == null ? "" : value.Account.SmtpAddress, RegistryValueKind.String);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +190,8 @@ namespace Acacia.Features.FreeBusy
|
|||||||
if (account != null && handler.Contacts != null)
|
if (account != null && handler.Contacts != null)
|
||||||
{
|
{
|
||||||
// Look for the email address. If found, use the account associated with the GAB
|
// Look for the email address. If found, use the account associated with the GAB
|
||||||
ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>();
|
using (ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>())
|
||||||
|
{
|
||||||
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
|
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
|
||||||
using (IItem result = search.SearchOne())
|
using (IItem result = search.SearchOne())
|
||||||
{
|
{
|
||||||
@ -201,6 +202,7 @@ namespace Acacia.Features.FreeBusy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fall back to default account
|
// Fall back to default account
|
||||||
return DefaultAccount;
|
return DefaultAccount;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -39,7 +38,7 @@ namespace Acacia.Features.GAB
|
|||||||
private readonly Dictionary<string, GABHandler> _gabsByDomainName = new Dictionary<string, GABHandler>();
|
private readonly Dictionary<string, GABHandler> _gabsByDomainName = new Dictionary<string, GABHandler>();
|
||||||
private readonly HashSet<string> _gabFolders = new HashSet<string>();
|
private readonly HashSet<string> _gabFolders = new HashSet<string>();
|
||||||
private readonly HashSet<string> _domains = new HashSet<string>();
|
private readonly HashSet<string> _domains = new HashSet<string>();
|
||||||
private ZPushLocalStore _store;
|
private IStore _store;
|
||||||
private int _processing;
|
private int _processing;
|
||||||
|
|
||||||
public FeatureGAB()
|
public FeatureGAB()
|
||||||
@ -63,9 +62,12 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void Startup()
|
public override void Startup()
|
||||||
|
{
|
||||||
|
if (SuppressModifications && MailEvents != null)
|
||||||
{
|
{
|
||||||
MailEvents.BeforeDelete += SuppressEventHandler_Delete;
|
MailEvents.BeforeDelete += SuppressEventHandler_Delete;
|
||||||
MailEvents.Write += SuppressEventHandler_Modify;
|
MailEvents.Write += SuppressEventHandler_Modify;
|
||||||
|
}
|
||||||
Watcher.AccountDiscovered += AccountDiscovered;
|
Watcher.AccountDiscovered += AccountDiscovered;
|
||||||
Watcher.AccountRemoved += AccountRemoved;
|
Watcher.AccountRemoved += AccountRemoved;
|
||||||
Watcher.AccountsScanned += AccountsScanned;
|
Watcher.AccountsScanned += AccountsScanned;
|
||||||
@ -118,6 +120,15 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
private static readonly BoolOption OPTION_PROCESS_MESSAGE = new BoolOption("ProcessMessage", true);
|
private static readonly BoolOption OPTION_PROCESS_MESSAGE = new BoolOption("ProcessMessage", true);
|
||||||
|
|
||||||
|
[AcaciaOption("If disabled, existing contacts are not deleted when a chunk is processed. " +
|
||||||
|
"This should only be disabled for debug purposes.")]
|
||||||
|
public bool ProcessMessageDeleteExisting
|
||||||
|
{
|
||||||
|
get { return GetOption(OPTION_PROCESS_MESSAGE_DELETE_EXISTING); }
|
||||||
|
set { SetOption(OPTION_PROCESS_MESSAGE_DELETE_EXISTING, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption OPTION_PROCESS_MESSAGE_DELETE_EXISTING = new BoolOption("ProcessMessageDeleteExisting", true);
|
||||||
|
|
||||||
[AcaciaOption("If disabled, contacts are not created from incoming GAB messages. " +
|
[AcaciaOption("If disabled, contacts are not created from incoming GAB messages. " +
|
||||||
"This should only be disabled for debug purposes.")]
|
"This should only be disabled for debug purposes.")]
|
||||||
public bool CreateContacts
|
public bool CreateContacts
|
||||||
@ -173,6 +184,42 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
private static readonly BoolOption OPTION_CHECK_UNUSED = new BoolOption("CheckUnused", true);
|
private static readonly BoolOption OPTION_CHECK_UNUSED = new BoolOption("CheckUnused", true);
|
||||||
|
|
||||||
|
[AcaciaOption("If disabled, existing contacts are not cleared before new contacts are created. " +
|
||||||
|
"This should only be disabled for debug purposes.")]
|
||||||
|
public bool ClearContacts
|
||||||
|
{
|
||||||
|
get { return GetOption(OPTION_CLEAR_CONTACTS); }
|
||||||
|
set { SetOption(OPTION_CLEAR_CONTACTS, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption OPTION_CLEAR_CONTACTS = new BoolOption("ClearContacts", true);
|
||||||
|
|
||||||
|
[AcaciaOption("If disabled, existing contact folders are not deleted before new contacts are created. " +
|
||||||
|
"This should only be disabled for debug purposes.")]
|
||||||
|
public bool DeleteExistingFolder
|
||||||
|
{
|
||||||
|
get { return GetOption(OPTION_DELETE_EXISTING_FOLDER); }
|
||||||
|
set { SetOption(OPTION_DELETE_EXISTING_FOLDER, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption OPTION_DELETE_EXISTING_FOLDER = new BoolOption("DeleteExistingFolder", true);
|
||||||
|
|
||||||
|
[AcaciaOption("If disabled, deleted items are not removed from the waste basket. " +
|
||||||
|
"This should only be disabled for debug purposes.")]
|
||||||
|
public bool EmptyDeletedItems
|
||||||
|
{
|
||||||
|
get { return GetOption(OPTION_EMPTY_DELETED_ITEMS); }
|
||||||
|
set { SetOption(OPTION_EMPTY_DELETED_ITEMS, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption OPTION_EMPTY_DELETED_ITEMS = new BoolOption("EmptyDeletedItems", true);
|
||||||
|
|
||||||
|
[AcaciaOption("If enabled, modifications to the GAB folder are suppressed. " +
|
||||||
|
"This should only be disabled for debug purposes.")]
|
||||||
|
public bool SuppressModifications
|
||||||
|
{
|
||||||
|
get { return GetOption(OPTION_SUPPRESS_MODIFICATIONS); }
|
||||||
|
set { SetOption(OPTION_SUPPRESS_MODIFICATIONS, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption OPTION_SUPPRESS_MODIFICATIONS = new BoolOption("SuppressModifications", true);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Modification suppression
|
#region Modification suppression
|
||||||
@ -203,7 +250,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);
|
||||||
}
|
}
|
||||||
@ -233,16 +280,19 @@ namespace Acacia.Features.GAB
|
|||||||
/// <param name="cancel"></param>
|
/// <param name="cancel"></param>
|
||||||
private void DoSuppressEvent(IItem item, ref bool cancel)
|
private void DoSuppressEvent(IItem item, ref bool cancel)
|
||||||
{
|
{
|
||||||
if (item != null)
|
// TODO: Find and close the inspector
|
||||||
|
/*if (item != null)
|
||||||
{
|
{
|
||||||
foreach (Inspector inspector in App.Inspectors)
|
foreach (Inspector inspector in ThisAddIn.Instance.Inspectors)
|
||||||
{
|
{
|
||||||
if (item.EntryId == inspector.CurrentItem.EntryID)
|
if (item.EntryId == inspector.CurrentItem.EntryID)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
// Show message and cancel event
|
||||||
MessageBox.Show(StringUtil.GetResourceString("GABEvent_Body"),
|
MessageBox.Show(StringUtil.GetResourceString("GABEvent_Body"),
|
||||||
StringUtil.GetResourceString("GABEvent_Title"),
|
StringUtil.GetResourceString("GABEvent_Title"),
|
||||||
MessageBoxButtons.OK,
|
MessageBoxButtons.OK,
|
||||||
@ -263,16 +313,15 @@ namespace Acacia.Features.GAB
|
|||||||
BeginProcessing();
|
BeginProcessing();
|
||||||
|
|
||||||
// Delete any contacts folders in the local store
|
// Delete any contacts folders in the local store
|
||||||
using (ZPushLocalStore store = ZPushLocalStore.GetInstance(App))
|
if (DeleteExistingFolder)
|
||||||
|
{
|
||||||
|
using (IStore store = ZPushLocalStore.GetInstance(ThisAddIn.Instance))
|
||||||
{
|
{
|
||||||
if (store != null)
|
if (store != null)
|
||||||
{
|
{
|
||||||
using (IFolder root = store.RootFolder)
|
using (IFolder root = store.GetRootFolder())
|
||||||
{
|
{
|
||||||
foreach (IFolder folder in root.GetSubFolders<IFolder>())
|
foreach (IFolder folder in root.GetSubFolders<IFolder>().DisposeEnum())
|
||||||
{
|
|
||||||
// TODO: let enumerator handle this
|
|
||||||
using (folder)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -293,10 +342,14 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do the resync
|
// Do the resync
|
||||||
|
int remaining = _gabsByDomainName.Count;
|
||||||
foreach (GABHandler gab in _gabsByDomainName.Values)
|
foreach (GABHandler gab in _gabsByDomainName.Values)
|
||||||
{
|
{
|
||||||
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
|
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
|
||||||
Tasks.Task(this, "FullResync", () => gab.FullResync());
|
Tasks.Task(this, "FullResync", () =>
|
||||||
|
{
|
||||||
|
gab.FullResync();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -353,12 +406,12 @@ namespace Acacia.Features.GAB
|
|||||||
_store.Dispose();
|
_store.Dispose();
|
||||||
_store = null;
|
_store = null;
|
||||||
}
|
}
|
||||||
_store = ZPushLocalStore.GetInstance(App);
|
_store = ZPushLocalStore.GetInstance(ThisAddIn.Instance);
|
||||||
if (_store == null)
|
if (_store == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Try to find the existing GAB
|
// Try to find the existing GAB
|
||||||
using (IFolder root = _store.RootFolder)
|
using (IFolder root = _store.GetRootFolder())
|
||||||
{
|
{
|
||||||
IAddressBook gab = FindGABForDomain(root, domainName);
|
IAddressBook gab = FindGABForDomain(root, domainName);
|
||||||
if (gab == null)
|
if (gab == null)
|
||||||
@ -376,23 +429,29 @@ 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);
|
||||||
|
|
||||||
|
if (SuppressModifications)
|
||||||
|
{
|
||||||
// Hook BeforeMove event to prevent modifications
|
// Hook BeforeMove event to prevent modifications
|
||||||
// TODO: use ZPushWatcher for this?
|
// TODO: use ZPushWatcher for this?
|
||||||
gab.BeforeItemMove += SuppressMoveEventHandler;
|
gab.BeforeItemMove += SuppressMoveEventHandler;
|
||||||
|
}
|
||||||
|
|
||||||
return gab;
|
return gab;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisposeGABContacts(IAddressBook gab)
|
private void DisposeGABContacts(IAddressBook gab)
|
||||||
|
{
|
||||||
|
if (SuppressModifications)
|
||||||
{
|
{
|
||||||
// Unhook the event to prevent the gab lingering in memory
|
// Unhook the event to prevent the gab lingering in memory
|
||||||
gab.BeforeItemMove -= SuppressMoveEventHandler;
|
gab.BeforeItemMove -= SuppressMoveEventHandler;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static GABInfo GetGABContactsFolderInfo(IFolder folder)
|
public static GABInfo GetGABContactsFolderInfo(IFolder folder)
|
||||||
{
|
{
|
||||||
@ -410,7 +469,7 @@ namespace Acacia.Features.GAB
|
|||||||
private void AccountDiscovered(ZPushAccount zpush)
|
private void AccountDiscovered(ZPushAccount zpush)
|
||||||
{
|
{
|
||||||
Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName);
|
Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName);
|
||||||
_domains.Add(zpush.DomainName);
|
_domains.Add(zpush.Account.DomainName);
|
||||||
|
|
||||||
zpush.ConfirmedChanged += (z) =>
|
zpush.ConfirmedChanged += (z) =>
|
||||||
{
|
{
|
||||||
@ -469,12 +528,12 @@ namespace Acacia.Features.GAB
|
|||||||
_store.Dispose();
|
_store.Dispose();
|
||||||
_store = null;
|
_store = null;
|
||||||
}
|
}
|
||||||
_store = ZPushLocalStore.GetInstance(App);
|
_store = ZPushLocalStore.GetInstance(ThisAddIn.Instance);
|
||||||
if (_store == null)
|
if (_store == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool deletedSomething = false;
|
bool deletedSomething = false;
|
||||||
using (IFolder root = _store.RootFolder)
|
using (IFolder root = _store.GetRootFolder())
|
||||||
{
|
{
|
||||||
foreach (IFolder subfolder in root.GetSubFolders<IFolder>())
|
foreach (IFolder subfolder in root.GetSubFolders<IFolder>())
|
||||||
{
|
{
|
||||||
@ -484,7 +543,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;
|
||||||
@ -500,7 +559,7 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deletedSomething)
|
if (deletedSomething)
|
||||||
EmptyDeletedItems();
|
DoEmptyDeletedItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckGABRemoved()
|
private void CheckGABRemoved()
|
||||||
@ -535,14 +594,14 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EmptyDeletedItems();
|
DoEmptyDeletedItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterGABAccount(ZPushAccount account, IFolder folder)
|
private void RegisterGABAccount(ZPushAccount account, IFolder folder)
|
||||||
{
|
{
|
||||||
// Determine the domain name
|
// Determine the domain name
|
||||||
string domain = account.DomainName;
|
string domain = account.Account.DomainName;
|
||||||
|
|
||||||
// Could already be registered if there are multiple accounts on the same domain
|
// Could already be registered if there are multiple accounts on the same domain
|
||||||
GABHandler gab;
|
GABHandler gab;
|
||||||
@ -573,7 +632,7 @@ namespace Acacia.Features.GAB
|
|||||||
|
|
||||||
private void ZPushChannelAvailable(IFolder folder)
|
private void ZPushChannelAvailable(IFolder folder)
|
||||||
{
|
{
|
||||||
using (IStore store = folder.Store)
|
using (IStore store = folder.GetStore())
|
||||||
{
|
{
|
||||||
Logger.Instance.Debug(this, "Z-Push channel available: {0} on {1}", folder, store.DisplayName);
|
Logger.Instance.Debug(this, "Z-Push channel available: {0} on {1}", folder, store.DisplayName);
|
||||||
|
|
||||||
@ -606,7 +665,7 @@ namespace Acacia.Features.GAB
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
gab.Process(item);
|
gab.Process(item);
|
||||||
EmptyDeletedItems();
|
DoEmptyDeletedItems();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -615,8 +674,11 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmptyDeletedItems()
|
private void DoEmptyDeletedItems()
|
||||||
{
|
{
|
||||||
|
if (!EmptyDeletedItems)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_store != null)
|
if (_store != null)
|
||||||
_store.EmptyDeletedItems();
|
_store.EmptyDeletedItems();
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace Acacia.Features.GAB
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
using(IStore store = Folder.Store)
|
using(IStore store = Folder.GetStore())
|
||||||
return store.DisplayName;
|
return store.DisplayName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,6 +136,13 @@ namespace Acacia.Features.GAB
|
|||||||
|
|
||||||
private void ClearContacts()
|
private void ClearContacts()
|
||||||
{
|
{
|
||||||
|
if (!_feature.ClearContacts)
|
||||||
|
{
|
||||||
|
using (IStorageItem item = GetIndexItem())
|
||||||
|
item?.Delete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Contacts != null)
|
if (Contacts != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -193,12 +200,10 @@ namespace Acacia.Features.GAB
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Process the messages
|
// Process the messages
|
||||||
foreach (IItem item in Folder.Items)
|
foreach (IZPushItem item in Folder.Items.Typed<IZPushItem>())
|
||||||
{
|
{
|
||||||
// TODO: make type-checking iterator?
|
// Store the entry id to fetch again later, the item will be disposed
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -213,7 +218,6 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public const string PROP_LAST_PROCESSED = "ZPushLastProcessed";
|
public const string PROP_LAST_PROCESSED = "ZPushLastProcessed";
|
||||||
public const string PROP_SEQUENCE = "ZPushSequence";
|
public const string PROP_SEQUENCE = "ZPushSequence";
|
||||||
@ -260,20 +264,21 @@ namespace Acacia.Features.GAB
|
|||||||
Logger.Instance.Trace(this, "Processing: {0} - {1} - {2}", item.Subject, item.Location, lastProcessed);
|
Logger.Instance.Trace(this, "Processing: {0} - {1} - {2}", item.Subject, item.Location, lastProcessed);
|
||||||
_feature?.BeginProcessing();
|
_feature?.BeginProcessing();
|
||||||
try
|
try
|
||||||
|
{
|
||||||
|
if (_feature.ProcessMessageDeleteExisting)
|
||||||
{
|
{
|
||||||
// Delete the old contacts from this chunk
|
// Delete the old contacts from this chunk
|
||||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
using (ISearch<IItem> search = Contacts.Search<IItem>())
|
||||||
|
{
|
||||||
search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks);
|
search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks);
|
||||||
search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk);
|
search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk);
|
||||||
foreach (IItem oldItem in search.Search())
|
foreach (IItem oldItem in search.Search())
|
||||||
{
|
|
||||||
// TODO: Search should handle this, like folder enumeration
|
|
||||||
using (oldItem)
|
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject);
|
Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject);
|
||||||
oldItem.Delete();
|
oldItem.Delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create the new contacts
|
// Create the new contacts
|
||||||
ProcessChunkBody(item, index);
|
ProcessChunkBody(item, index);
|
||||||
@ -297,7 +302,7 @@ namespace Acacia.Features.GAB
|
|||||||
{
|
{
|
||||||
using (IStorageItem index = GetIndexItem())
|
using (IStorageItem index = GetIndexItem())
|
||||||
{
|
{
|
||||||
return index?.GetUserProperty<int>(PROP_CURRENT_SEQUENCE)?.Value;
|
return index?.GetUserProperty<int?>(PROP_CURRENT_SEQUENCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@ -306,7 +311,7 @@ namespace Acacia.Features.GAB
|
|||||||
{
|
{
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = value.Value;
|
index.SetUserProperty<int>(PROP_CURRENT_SEQUENCE, value.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -316,23 +321,26 @@ namespace Acacia.Features.GAB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IItem FindNewestChunk()
|
private ChunkIndex? FindNewestChunkIndex()
|
||||||
{
|
{
|
||||||
if (Folder == null)
|
if (Folder == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Scan a few of the newest items, in case there is some junk in the ZPush folder
|
// Scan a few of the newest items, in case there is some junk in the ZPush folder
|
||||||
// TODO: this shouldn't happen in production.
|
// This shouldn't happen in production, but check anyway.
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach(IItem item in Folder.ItemsSorted("LastModificationTime", true))
|
foreach(IItem item in Folder.Items.Sort("LastModificationTime", true))
|
||||||
{
|
{
|
||||||
if (ChunkIndex.Parse(item.Subject) != null)
|
using (item)
|
||||||
return item;
|
{
|
||||||
item.Dispose();
|
ChunkIndex? index = ChunkIndex.Parse(item.Subject);
|
||||||
|
if (index != null)
|
||||||
|
return index;
|
||||||
if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK)
|
if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK)
|
||||||
return null;
|
return null;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,16 +349,17 @@ namespace Acacia.Features.GAB
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Find the newest chunk
|
// Find the newest chunk
|
||||||
using (IItem newest = FindNewestChunk())
|
ChunkIndex? newestChunkIndex = FindNewestChunkIndex();
|
||||||
|
if (newestChunkIndex == null)
|
||||||
{
|
{
|
||||||
if (newest == null)
|
|
||||||
CurrentSequence = null;
|
CurrentSequence = null;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Newest chunk: {0}", newest.Subject);
|
Logger.Instance.Trace(this, "Newest chunk: {0}", newestChunkIndex.Value);
|
||||||
ChunkIndex? newestChunkIndex = ChunkIndex.Parse(newest.Subject);
|
|
||||||
|
|
||||||
if (!CurrentSequence.HasValue || CurrentSequence.Value != newestChunkIndex?.numberOfChunks)
|
int? currentSequence = CurrentSequence;
|
||||||
|
if (!currentSequence.HasValue || currentSequence.Value != newestChunkIndex?.numberOfChunks)
|
||||||
{
|
{
|
||||||
// Sequence has changed. Delete contacts
|
// Sequence has changed. Delete contacts
|
||||||
Logger.Instance.Trace(this, "Rechunked, deleting contacts");
|
Logger.Instance.Trace(this, "Rechunked, deleting contacts");
|
||||||
@ -370,15 +379,14 @@ namespace Acacia.Features.GAB
|
|||||||
int numberOfChunks = newestChunkIndex.Value.numberOfChunks;
|
int numberOfChunks = newestChunkIndex.Value.numberOfChunks;
|
||||||
using (IStorageItem index = GetIndexItem())
|
using (IStorageItem index = GetIndexItem())
|
||||||
{
|
{
|
||||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = numberOfChunks;
|
index.SetUserProperty(PROP_CURRENT_SEQUENCE, numberOfChunks);
|
||||||
index.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = CreateChunkStateString(numberOfChunks);
|
index.SetUserProperty(PROP_LAST_PROCESSED, CreateChunkStateString(numberOfChunks));
|
||||||
index.Save();
|
index.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Exception determining sequence: {0}", e);
|
Logger.Instance.Trace(this, "Exception determining sequence: {0}", e);
|
||||||
@ -402,7 +410,7 @@ namespace Acacia.Features.GAB
|
|||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return null;
|
return null;
|
||||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED);
|
||||||
if (string.IsNullOrEmpty(state))
|
if (string.IsNullOrEmpty(state))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -420,7 +428,7 @@ namespace Acacia.Features.GAB
|
|||||||
{
|
{
|
||||||
using (IStorageItem item = GetIndexItem())
|
using (IStorageItem item = GetIndexItem())
|
||||||
{
|
{
|
||||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED);
|
||||||
string[] parts;
|
string[] parts;
|
||||||
if (string.IsNullOrEmpty(state))
|
if (string.IsNullOrEmpty(state))
|
||||||
parts = new string[index.numberOfChunks];
|
parts = new string[index.numberOfChunks];
|
||||||
@ -434,7 +442,7 @@ namespace Acacia.Features.GAB
|
|||||||
parts[index.chunk] = partState;
|
parts[index.chunk] = partState;
|
||||||
string combined = string.Join(";", parts);
|
string combined = string.Join(";", parts);
|
||||||
|
|
||||||
item.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = combined;
|
item.SetUserProperty(PROP_LAST_PROCESSED, combined);
|
||||||
item.Save();
|
item.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -598,7 +606,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);
|
||||||
}
|
}
|
||||||
@ -613,17 +621,19 @@ namespace Acacia.Features.GAB
|
|||||||
|
|
||||||
private IItem FindItemById(string id)
|
private IItem FindItemById(string id)
|
||||||
{
|
{
|
||||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
using (ISearch<IItem> search = Contacts.Search<IItem>())
|
||||||
|
{
|
||||||
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
|
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
|
||||||
return search.SearchOne();
|
return search.SearchOne();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetItemStandard(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)
|
private void SetItemStandard(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)
|
||||||
{
|
{
|
||||||
// Set the chunk data
|
// Set the chunk data
|
||||||
item.GetUserProperty<int>(PROP_SEQUENCE, true).Value = index.numberOfChunks;
|
item.SetUserProperty(PROP_SEQUENCE, index.numberOfChunks);
|
||||||
item.GetUserProperty<int>(PROP_CHUNK, true).Value = index.chunk;
|
item.SetUserProperty(PROP_CHUNK, index.chunk);
|
||||||
item.GetUserProperty<string>(PROP_GAB_ID, true).Value = id;
|
item.SetUserProperty(PROP_GAB_ID, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddGroupMember(IDistributionList group, IItem item)
|
private void AddGroupMember(IDistributionList group, IItem item)
|
||||||
@ -653,7 +663,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);
|
||||||
|
@ -18,7 +18,6 @@ using Acacia.Stubs;
|
|||||||
using Acacia.Stubs.OutlookWrappers;
|
using Acacia.Stubs.OutlookWrappers;
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
@ -84,7 +83,7 @@ namespace Acacia.Features.Notes
|
|||||||
PatchIfConfirmed(folder);
|
PatchIfConfirmed(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsNotesFolder(OutlookConstants.SyncType type)
|
private bool IsNotesFolder(OutlookConstants.SyncType? type)
|
||||||
{
|
{
|
||||||
return type == OutlookConstants.SyncType.Note || type == OutlookConstants.SyncType.UserNote;
|
return type == OutlookConstants.SyncType.Note || type == OutlookConstants.SyncType.UserNote;
|
||||||
}
|
}
|
||||||
@ -93,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)
|
||||||
{
|
{
|
||||||
@ -122,13 +121,13 @@ namespace Acacia.Features.Notes
|
|||||||
Logger.Instance.Trace(this, "PatchFolder: {0}", folderId);
|
Logger.Instance.Trace(this, "PatchFolder: {0}", folderId);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId))
|
||||||
{
|
{
|
||||||
if (folder == null)
|
if (folder == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Patch if needed
|
// Patch if needed
|
||||||
OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder);
|
OutlookConstants.SyncType? type = FolderUtils.GetFolderSyncType(folder);
|
||||||
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
||||||
if (IsNotesFolder(type))
|
if (IsNotesFolder(type))
|
||||||
{
|
{
|
||||||
@ -168,13 +167,13 @@ namespace Acacia.Features.Notes
|
|||||||
Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId);
|
Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId))
|
||||||
{
|
{
|
||||||
if (folder == null)
|
if (folder == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Unpatch if needed
|
// Unpatch if needed
|
||||||
OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder, true);
|
OutlookConstants.SyncType? type = FolderUtils.GetFolderSyncType(folder, true);
|
||||||
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
||||||
// Unpatch only if the original type is a notes folder, but the current type isn't
|
// Unpatch only if the original type is a notes folder, but the current type isn't
|
||||||
if (IsNotesFolder(type) && !IsNotesFolder(FolderUtils.GetFolderSyncType(folder)))
|
if (IsNotesFolder(type) && !IsNotesFolder(FolderUtils.GetFolderSyncType(folder)))
|
||||||
@ -220,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(
|
||||||
|
@ -19,7 +19,6 @@ using Acacia.UI.Outlook;
|
|||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using Acacia.ZPush.Connect;
|
using Acacia.ZPush.Connect;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -48,6 +47,12 @@ namespace Acacia.Features.OutOfOffice
|
|||||||
Watcher.ZPushAccountChange += Watcher_ZPushAccountChange;
|
Watcher.ZPushAccountChange += Watcher_ZPushAccountChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override public void GetCapabilities(ZPushCapabilities caps)
|
||||||
|
{
|
||||||
|
caps.Add("oof");
|
||||||
|
caps.Add("ooftime");
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsOOFEnabled(ActiveSync.SettingsOOF settings)
|
private static bool IsOOFEnabled(ActiveSync.SettingsOOF settings)
|
||||||
{
|
{
|
||||||
if (settings == null)
|
if (settings == null)
|
||||||
@ -227,7 +232,7 @@ namespace Acacia.Features.OutOfOffice
|
|||||||
if (oof.State != ActiveSync.OOFState.Disabled)
|
if (oof.State != ActiveSync.OOFState.Disabled)
|
||||||
{
|
{
|
||||||
if (MessageBox.Show(
|
if (MessageBox.Show(
|
||||||
string.Format(Properties.Resources.OOFStartup_Message, account.SmtpAddress),
|
string.Format(Properties.Resources.OOFStartup_Message, account.Account.SmtpAddress),
|
||||||
Properties.Resources.OOFStartup_Title,
|
Properties.Resources.OOFStartup_Title,
|
||||||
MessageBoxButtons.YesNo,
|
MessageBoxButtons.YesNo,
|
||||||
MessageBoxIcon.Question
|
MessageBoxIcon.Question
|
||||||
|
@ -43,7 +43,7 @@ namespace Acacia.Features.OutOfOffice
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
// Add the email address to the title
|
// Add the email address to the title
|
||||||
Text = string.Format(Text, account.SmtpAddress);
|
Text = string.Format(Text, account.Account.SmtpAddress);
|
||||||
|
|
||||||
// Set the time formats
|
// Set the time formats
|
||||||
timeFrom.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
|
timeFrom.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
|
||||||
|
@ -22,7 +22,6 @@ using System.Threading.Tasks;
|
|||||||
using Acacia.Stubs;
|
using Acacia.Stubs;
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using static Acacia.DebugOptions;
|
using static Acacia.DebugOptions;
|
||||||
|
|
||||||
namespace Acacia.Features.ReplyFlags
|
namespace Acacia.Features.ReplyFlags
|
||||||
@ -48,17 +47,29 @@ namespace Acacia.Features.ReplyFlags
|
|||||||
if (ReadEvent)
|
if (ReadEvent)
|
||||||
{
|
{
|
||||||
// As a fallback, add an event handler to update the message when displaying it
|
// As a fallback, add an event handler to update the message when displaying it
|
||||||
|
if (MailEvents != null)
|
||||||
|
{
|
||||||
MailEvents.Read += UpdateReplyStatus;
|
MailEvents.Read += UpdateReplyStatus;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (SendEvents)
|
if (SendEvents)
|
||||||
{
|
{
|
||||||
// Hook reply and send events to update local state to server
|
// Hook reply and send events to update local state to server
|
||||||
|
if (MailEvents != null)
|
||||||
|
{
|
||||||
MailEvents.Reply += OnReply;
|
MailEvents.Reply += OnReply;
|
||||||
MailEvents.ReplyAll += OnReplyAll;
|
MailEvents.ReplyAll += OnReplyAll;
|
||||||
MailEvents.Forward += OnForwarded;
|
MailEvents.Forward += OnForwarded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public void GetCapabilities(ZPushCapabilities caps)
|
||||||
|
{
|
||||||
|
caps.Add("receiveflags");
|
||||||
|
caps.Add("sendflags");
|
||||||
|
}
|
||||||
|
|
||||||
[AcaciaOption("Enables or disables the handling of update events to mail items. When a mail item is " +
|
[AcaciaOption("Enables or disables the handling of update events to mail items. When a mail item is " +
|
||||||
"updated, it is checked to see if the reply flags are up to date. This is the main " +
|
"updated, it is checked to see if the reply flags are up to date. This is the main " +
|
||||||
|
@ -0,0 +1,138 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Stubs;
|
||||||
|
using Acacia.Stubs.OutlookWrappers;
|
||||||
|
using Acacia.Utils;
|
||||||
|
using Acacia.ZPush;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using static Acacia.DebugOptions;
|
||||||
|
|
||||||
|
namespace Acacia.Features.SecondaryContacts
|
||||||
|
{
|
||||||
|
[AcaciaOption("Provides the possibility to synchronise multiple contacts folders to and from a Z-Push server.")]
|
||||||
|
public class FeatureSecondaryContacts : Feature
|
||||||
|
{
|
||||||
|
private const string SUFFIX_CONTACTS = "\x200B";
|
||||||
|
|
||||||
|
private class FolderRegistrationSecondaryContacts : FolderRegistration
|
||||||
|
{
|
||||||
|
public FolderRegistrationSecondaryContacts(Feature feature) : base(feature)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsApplicable(IFolder folder)
|
||||||
|
{
|
||||||
|
// Check the sync type.
|
||||||
|
// Also allow again if the sync type is user contact, it may not have been fully patched.
|
||||||
|
if (FolderUtils.GetFolderSyncType(folder) != OutlookConstants.SyncType.Unknown &&
|
||||||
|
FolderUtils.GetFolderSyncType(folder) != OutlookConstants.SyncType.UserContact)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check the hidden suffix
|
||||||
|
if (!folder.Name.EndsWith(SUFFIX_CONTACTS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains the ids of folders for which we've shown a warning. This is both to prevent
|
||||||
|
// warning multiple times and to detect the case when the app has been restarted.
|
||||||
|
private readonly HashSet<string> _warnedFolders = new HashSet<string>();
|
||||||
|
|
||||||
|
public FeatureSecondaryContacts()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Startup()
|
||||||
|
{
|
||||||
|
Watcher.WatchFolder(new FolderRegistrationSecondaryContacts(this),
|
||||||
|
OnUnpatchedFolderDiscovered);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnpatchedFolderDiscovered(IFolder folder)
|
||||||
|
{
|
||||||
|
string strippedName = folder.Name.StripSuffix(SUFFIX_CONTACTS);
|
||||||
|
Logger.Instance.Debug(this, "Patching secondary contacts folder: {0}", strippedName);
|
||||||
|
|
||||||
|
// To patch we need to do the following
|
||||||
|
// 1) Update the sync type from 18 to 14
|
||||||
|
// 2) Update the container class from Note to Contact
|
||||||
|
// 3) Patch the name
|
||||||
|
// Note that the above steps need to be done in this order and individually for this to work.
|
||||||
|
//
|
||||||
|
// At some point after 2 we also need to restart Outlook to make it appear in the list of contact folders.
|
||||||
|
// So, when the folder is detected, we make it invisible and perform steps 1 and 2. We issue a warning
|
||||||
|
// that Outlook must be restarted. When the folder is detected again and is invisible, that means we've restarted
|
||||||
|
// At this point the name is patched and the folder is made visible.
|
||||||
|
|
||||||
|
if (!folder.AttrHidden)
|
||||||
|
{
|
||||||
|
// Stage 1
|
||||||
|
|
||||||
|
// Sync type
|
||||||
|
Logger.Instance.Trace(this, "Setting sync type");
|
||||||
|
folder.SetProperty(OutlookConstants.PR_EAS_SYNCTYPE, (int)OutlookConstants.SyncType.UserContact);
|
||||||
|
|
||||||
|
// Container type
|
||||||
|
Logger.Instance.Trace(this, "Setting container class");
|
||||||
|
folder.SetProperty(OutlookConstants.PR_CONTAINER_CLASS, "IPF.Contact");
|
||||||
|
|
||||||
|
// Make it invisible.
|
||||||
|
folder.AttrHidden = true;
|
||||||
|
|
||||||
|
Logger.Instance.Debug(this, "Patched secondary contacts folder: {0}", strippedName);
|
||||||
|
// Register and show a warning, if not already done.
|
||||||
|
// Note that patching may be done multiple times.
|
||||||
|
if (!_warnedFolders.Contains(folder.EntryID))
|
||||||
|
{
|
||||||
|
_warnedFolders.Add(folder.EntryID);
|
||||||
|
|
||||||
|
if (MessageBox.Show(StringUtil.GetResourceString("SecondaryContactsPatched_Body", strippedName),
|
||||||
|
StringUtil.GetResourceString("SecondaryContactsPatched_Title"),
|
||||||
|
MessageBoxButtons.YesNo,
|
||||||
|
MessageBoxIcon.Warning
|
||||||
|
) == DialogResult.Yes)
|
||||||
|
{
|
||||||
|
ThisAddIn.Instance.Restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If _warnedFolders does not contain the folder (and it's hidden), this means Outlook was restarted.
|
||||||
|
else if (!_warnedFolders.Contains(folder.EntryID))
|
||||||
|
{
|
||||||
|
// Stage 2
|
||||||
|
|
||||||
|
// Patch the name
|
||||||
|
Logger.Instance.Trace(this, "Patching name");
|
||||||
|
folder.Name = strippedName;
|
||||||
|
|
||||||
|
// Show it
|
||||||
|
folder.AttrHidden = false;
|
||||||
|
Logger.Instance.Debug(this, "Shown secondary contacts folder: {0}", strippedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,6 @@ using System.Threading.Tasks;
|
|||||||
using Acacia.Stubs;
|
using Acacia.Stubs;
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Features.SharedFolders;
|
using Acacia.Features.SharedFolders;
|
||||||
using Acacia.ZPush.API.SharedFolders;
|
using Acacia.ZPush.API.SharedFolders;
|
||||||
using static Acacia.DebugOptions;
|
using static Acacia.DebugOptions;
|
||||||
@ -30,7 +29,7 @@ using static Acacia.DebugOptions;
|
|||||||
namespace Acacia.Features.SendAs
|
namespace Acacia.Features.SendAs
|
||||||
{
|
{
|
||||||
[AcaciaOption("Provides the ability to select different senders for Z-Push accounts.")]
|
[AcaciaOption("Provides the ability to select different senders for Z-Push accounts.")]
|
||||||
public class FeatureSendAs : FeatureDisabled
|
public class FeatureSendAs : Feature
|
||||||
{
|
{
|
||||||
private FeatureSharedFolders _sharedFolders;
|
private FeatureSharedFolders _sharedFolders;
|
||||||
|
|
||||||
@ -49,24 +48,30 @@ namespace Acacia.Features.SendAs
|
|||||||
private static readonly BoolOption OPTION_SEND_AS_OWNER = new BoolOption("SendAsOwner", true);
|
private static readonly BoolOption OPTION_SEND_AS_OWNER = new BoolOption("SendAsOwner", true);
|
||||||
|
|
||||||
public override void Startup()
|
public override void Startup()
|
||||||
|
{
|
||||||
|
if (MailEvents != null)
|
||||||
{
|
{
|
||||||
MailEvents.ItemSend += MailEvents_ItemSend;
|
MailEvents.ItemSend += MailEvents_ItemSend;
|
||||||
|
}
|
||||||
|
|
||||||
if (SendAsOwner)
|
if (SendAsOwner)
|
||||||
{
|
{
|
||||||
// Need shared folders for automatic sender selection
|
// Need shared folders for automatic sender selection
|
||||||
_sharedFolders = ThisAddIn.Instance.GetFeature<FeatureSharedFolders>();
|
_sharedFolders = ThisAddIn.Instance.GetFeature<FeatureSharedFolders>();
|
||||||
if (_sharedFolders != null)
|
if (_sharedFolders != null)
|
||||||
|
{
|
||||||
|
if (MailEvents != null)
|
||||||
{
|
{
|
||||||
MailEvents.Respond += MailEvents_Respond;
|
MailEvents.Respond += MailEvents_Respond;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void MailEvents_Respond(IMailItem mail, IMailItem response)
|
private void MailEvents_Respond(IMailItem mail, IMailItem response)
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Responding to mail, checking");
|
Logger.Instance.Trace(this, "Responding to mail, checking");
|
||||||
using (IStore store = mail.Store)
|
using (IStore store = mail.GetStore())
|
||||||
{
|
{
|
||||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
||||||
Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush);
|
Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush);
|
||||||
@ -85,13 +90,16 @@ namespace Acacia.Features.SendAs
|
|||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName);
|
Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName);
|
||||||
// It's a shared folder, use the owner as the sender if possible
|
// It's a shared folder, use the owner as the sender if possible
|
||||||
// TODO: make a wrapper for this
|
using (IRecipient recip = ThisAddIn.Instance.ResolveRecipient(shared.Store.UserName))
|
||||||
var recip = ThisAddIn.Instance.Application.Session.CreateRecipient(shared.Store.UserName);
|
|
||||||
Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name);
|
|
||||||
if (recip != null && recip.Resolve())
|
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Sending as: {0}", recip.AddressEntry.Address);
|
Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name);
|
||||||
response.SetSender(recip.AddressEntry);
|
if (recip != null && recip.IsResolved)
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(this, "Sending as: {0}", recip.Address);
|
||||||
|
using (IAddressEntry address = recip.GetAddressEntry())
|
||||||
|
{
|
||||||
|
response.SetSender(address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -102,16 +110,17 @@ namespace Acacia.Features.SendAs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void MailEvents_ItemSend(IMailItem item, ref bool cancel)
|
private void MailEvents_ItemSend(IMailItem item, ref bool cancel)
|
||||||
{
|
{
|
||||||
using (IStore store = item.Store)
|
using (IStore store = item.GetStore())
|
||||||
{
|
{
|
||||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
||||||
if (zpush != null)
|
if (zpush != null)
|
||||||
{
|
{
|
||||||
string address = item.SenderEmailAddress;
|
string address = item.SenderEmailAddress;
|
||||||
if (address != null && address != zpush.SmtpAddress)
|
if (address != null && address != zpush.Account.SmtpAddress)
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "SendAs: {0}: {1}", address, item.SenderName);
|
Logger.Instance.Trace(this, "SendAs: {0}: {1}", address, item.SenderName);
|
||||||
item.SetProperty(Constants.ZPUSH_SEND_AS, address);
|
item.SetProperty(Constants.ZPUSH_SEND_AS, address);
|
||||||
|
@ -71,7 +71,7 @@ namespace Acacia.Features.SharedFolders
|
|||||||
).Images;
|
).Images;
|
||||||
|
|
||||||
// Add the email address to the title
|
// Add the email address to the title
|
||||||
Text = string.Format(Text, account.SmtpAddress);
|
Text = string.Format(Text, account.Account.SmtpAddress);
|
||||||
|
|
||||||
// Set up options
|
// Set up options
|
||||||
ShowOptions(new KTreeNode[0]);
|
ShowOptions(new KTreeNode[0]);
|
||||||
@ -191,7 +191,7 @@ namespace Acacia.Features.SharedFolders
|
|||||||
ctx.AddBusy(-count);
|
ctx.AddBusy(-count);
|
||||||
|
|
||||||
// Sync account
|
// Sync account
|
||||||
_account.SendReceive();
|
_account.Account.SendReceive();
|
||||||
|
|
||||||
// Show success
|
// Show success
|
||||||
ShowCompletion(Properties.Resources.SharedFolders_Applying_Success);
|
ShowCompletion(Properties.Resources.SharedFolders_Applying_Success);
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
|
||||||
|
using Acacia.Native.MAPI;
|
||||||
|
/// Copyright 2016 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -13,7 +15,6 @@
|
|||||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.UI;
|
using Acacia.UI;
|
||||||
using Acacia.UI.Outlook;
|
using Acacia.UI.Outlook;
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
@ -73,14 +74,6 @@ namespace Acacia.Features.WebApp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Check_AutoDiscover(ZPushAccount account)
|
|
||||||
{
|
|
||||||
AutoDiscover(account);
|
|
||||||
|
|
||||||
// Update button state
|
|
||||||
AccountChange(account);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenWebApp()
|
private void OpenWebApp()
|
||||||
{
|
{
|
||||||
ZPushAccount account = Watcher.CurrentZPushAccount();
|
ZPushAccount account = Watcher.CurrentZPushAccount();
|
||||||
@ -107,15 +100,15 @@ namespace Acacia.Features.WebApp
|
|||||||
// Perform a cached auto discover
|
// Perform a cached auto discover
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.DomainName);
|
Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.Account.DomainName);
|
||||||
string url = PerformAutoDiscover(account);
|
string url = PerformAutoDiscover(account);
|
||||||
Logger.Instance.Debug(this, "Finished kdiscover: {0}: {1}", account.DomainName, url);
|
Logger.Instance.Debug(this, "Finished kdiscover: {0}: {1}", account.Account.DomainName, url);
|
||||||
account.SetFeatureData(this, TXT_KDISCOVER, new URLCached(url));
|
account.SetFeatureData(this, TXT_KDISCOVER, new URLCached(url));
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
Logger.Instance.Warning(this, "Exception during kdiscover: {0}: {1}", account.DomainName, e);
|
Logger.Instance.Warning(this, "Exception during kdiscover: {0}: {1}", account.Account.DomainName, e);
|
||||||
account.SetFeatureData(this, TXT_KDISCOVER, null);
|
account.SetFeatureData(this, TXT_KDISCOVER, null);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -124,7 +117,7 @@ namespace Acacia.Features.WebApp
|
|||||||
private string PerformAutoDiscover(ZPushAccount account)
|
private string PerformAutoDiscover(ZPushAccount account)
|
||||||
{
|
{
|
||||||
// Fetch the txt record
|
// Fetch the txt record
|
||||||
IList<string> txt = DnsUtil.GetTxtRecord(account.DomainName);
|
IList<string> txt = DnsUtil.GetTxtRecord(account.Account.DomainName);
|
||||||
if (txt == null)
|
if (txt == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ namespace Acacia
|
|||||||
get { return GetOption(null, THREADING); }
|
get { return GetOption(null, THREADING); }
|
||||||
set { SetOption(null, THREADING, value); }
|
set { SetOption(null, THREADING, value); }
|
||||||
}
|
}
|
||||||
private static readonly EnumOption<Threading> THREADING = new EnumOption<Threading>("Threading");
|
private static readonly EnumOption<Threading> THREADING = new EnumOption<Threading>("Threading", Threading.Background);
|
||||||
|
|
||||||
[AcaciaOption("Enables or disables ZPush account checking. To enable advanced features, it must be known " +
|
[AcaciaOption("Enables or disables ZPush account checking. To enable advanced features, it must be known " +
|
||||||
"which accounts use ZPush servers. This option checks responses from ActiveSync servers to " +
|
"which accounts use ZPush servers. This option checks responses from ActiveSync servers to " +
|
||||||
@ -118,6 +118,15 @@ namespace Acacia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[AcaciaOption("Enables or disables item event hooking." +
|
||||||
|
"Note that if this is disabled, several features may not work correctly.")]
|
||||||
|
virtual public bool HookItemEvents
|
||||||
|
{
|
||||||
|
get { return GetOption(null, HOOK_ITEM_EVENTS); }
|
||||||
|
set { SetOption(null, HOOK_ITEM_EVENTS, value); }
|
||||||
|
}
|
||||||
|
private static readonly BoolOption HOOK_ITEM_EVENTS = new BoolOption("HookItemEvents", true);
|
||||||
|
|
||||||
#region UI Options
|
#region UI Options
|
||||||
|
|
||||||
[AcaciaOption("Completely enables or disables modifications to the Outlook UI." +
|
[AcaciaOption("Completely enables or disables modifications to the Outlook UI." +
|
||||||
|
34
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOleWindow.cs
Normal file
34
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOleWindow.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/// Copyright 2017 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.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Native
|
||||||
|
{
|
||||||
|
[ComImport]
|
||||||
|
[Guid("00000114-0000-0000-C000-000000000046")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IOleWindow
|
||||||
|
{
|
||||||
|
void GetWindow(out IntPtr phwnd);
|
||||||
|
void ContextSensitiveHelp([In, MarshalAs(UnmanagedType.Bool)] bool fEnterMode);
|
||||||
|
}
|
||||||
|
}
|
486
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI.cs
Normal file
486
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI.cs
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Native.MAPI
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum SaveChangesFlags : UInt32
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
KEEP_OPEN_READONLY = 1,
|
||||||
|
KEEP_OPEN_READWRITE = 2,
|
||||||
|
FORCE_SAVE = 4,
|
||||||
|
MAPI_DEFERRED_ERRORS = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport]
|
||||||
|
[Guid("00020303-0000-0000-C000-000000000046")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IMAPIProp
|
||||||
|
{
|
||||||
|
void GetLastError(Int32 hResult, UInt32 flags, out IntPtr ptr);
|
||||||
|
void SaveChanges(SaveChangesFlags flags);
|
||||||
|
void GetProps();
|
||||||
|
void GetPropList();
|
||||||
|
void OpenProperty();
|
||||||
|
void SetProps();
|
||||||
|
void DeleteProps();
|
||||||
|
void CopyTo();
|
||||||
|
void CopyProps();
|
||||||
|
void GetNamesFromIDs();
|
||||||
|
void GetIDsFromNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct SBinary
|
||||||
|
{
|
||||||
|
public uint cb;
|
||||||
|
public byte* ptr;
|
||||||
|
|
||||||
|
public byte[] Unmarshal()
|
||||||
|
{
|
||||||
|
byte[] result = new byte[cb];
|
||||||
|
Marshal.Copy((IntPtr)ptr, result, 0, result.Length);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
byte[] b = Unmarshal();
|
||||||
|
return b.Length.ToString() + ":" + StringUtil.BytesToHex(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct SBinaryArray
|
||||||
|
{
|
||||||
|
public uint count;
|
||||||
|
public SBinary* ptr;
|
||||||
|
|
||||||
|
public byte[][] Unmarshal()
|
||||||
|
{
|
||||||
|
byte[][] result = new byte[count][];
|
||||||
|
for (uint i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
result[i] = ptr[i].Unmarshal();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PropType : ushort
|
||||||
|
{
|
||||||
|
BOOLEAN = 0x000B,
|
||||||
|
BINARY = 0x0102,
|
||||||
|
MV_BINARY = 1102,
|
||||||
|
DOUBLE = 0x0005,
|
||||||
|
LONG = 0x0003,
|
||||||
|
OBJECT = 0x000D,
|
||||||
|
STRING8 = 0x001E,
|
||||||
|
MV_STRING8 = 0x101E,
|
||||||
|
SYSTIME = 0x0040,
|
||||||
|
UNICODE = 0x001F,
|
||||||
|
MV_UNICODE = 0x101f
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
public struct PropTag
|
||||||
|
{
|
||||||
|
public PropType type;
|
||||||
|
public ushort prop;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "<" + prop.ToString("X4") + ":" + type + ">";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
unsafe public struct PropValue
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public PropTag ulPropTag;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
public uint dwAlignPad;
|
||||||
|
|
||||||
|
// short int i; /* case PT_I2 */
|
||||||
|
// LONG l; /* case PT_LONG */
|
||||||
|
// ULONG ul; /* alias for PT_LONG */
|
||||||
|
// LPVOID lpv; /* alias for PT_PTR */
|
||||||
|
// float flt; /* case PT_R4 */
|
||||||
|
// double dbl; /* case PT_DOUBLE */
|
||||||
|
// unsigned short int b; /* case PT_BOOLEAN */
|
||||||
|
[FieldOffset(8), MarshalAs(UnmanagedType.U2)]
|
||||||
|
public bool b;
|
||||||
|
|
||||||
|
// CURRENCY cur; /* case PT_CURRENCY */
|
||||||
|
// double at; /* case PT_APPTIME */
|
||||||
|
// FILETIME ft; /* case PT_SYSTIME */
|
||||||
|
|
||||||
|
// LPSTR lpszA; /* case PT_STRING8 */
|
||||||
|
[FieldOffset(8), MarshalAs(UnmanagedType.LPStr)]
|
||||||
|
public sbyte* lpszA;
|
||||||
|
|
||||||
|
// SBinary bin; /* case PT_BINARY */
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public SBinary bin;
|
||||||
|
|
||||||
|
// LPWSTR lpszW; /* case PT_UNICODE */
|
||||||
|
[FieldOffset(8), MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public char* lpszW;
|
||||||
|
|
||||||
|
// LPGUID lpguid; /* case PT_CLSID */
|
||||||
|
// LARGE_INTEGER li; /* case PT_I8 */
|
||||||
|
// SShortArray MVi; /* case PT_MV_I2 */
|
||||||
|
// SLongArray MVl; /* case PT_MV_LONG */
|
||||||
|
// SRealArray MVflt; /* case PT_MV_R4 */
|
||||||
|
// SDoubleArray MVdbl; /* case PT_MV_DOUBLE */
|
||||||
|
// SCurrencyArray MVcur; /* case PT_MV_CURRENCY */
|
||||||
|
// SAppTimeArray MVat; /* case PT_MV_APPTIME */
|
||||||
|
// SDateTimeArray MVft; /* case PT_MV_SYSTIME */
|
||||||
|
// SBinaryArray MVbin; /* case PT_MV_BINARY */
|
||||||
|
// SLPSTRArray MVszA; /* case PT_MV_STRING8 */
|
||||||
|
// SWStringArray MVszW; /* case PT_MV_UNICODE */
|
||||||
|
|
||||||
|
// SGuidArray MVguid; /* case PT_MV_CLSID */
|
||||||
|
// SLargeIntegerArray MVli; /* case PT_MV_I8 */
|
||||||
|
// SCODE err; /* case PT_ERROR */
|
||||||
|
// LONG x; /* case PT_NULL, PT_OBJECT (no usable value) */
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
switch(ulPropTag.type)
|
||||||
|
{
|
||||||
|
case PropType.BOOLEAN:
|
||||||
|
return b.ToString();
|
||||||
|
case PropType.STRING8:
|
||||||
|
return new string(lpszA);
|
||||||
|
case PropType.BINARY:
|
||||||
|
return bin.ToString();
|
||||||
|
//case PropType.UNICODE:
|
||||||
|
// return lpszW.ToString();
|
||||||
|
}
|
||||||
|
return "<unknown>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct CommentRestriction
|
||||||
|
{
|
||||||
|
public uint cValues;
|
||||||
|
public SRestriction* res;
|
||||||
|
public PropValue* prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct PropertyRestriction
|
||||||
|
{
|
||||||
|
public Acacia.Stubs.SearchOperation relop;
|
||||||
|
public PropTag ulPropTag;
|
||||||
|
public PropValue* prop;
|
||||||
|
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string indent = new string(' ', depth);
|
||||||
|
string s = indent + relop + ":" + ulPropTag.ToString();
|
||||||
|
s += ":" + prop->ToString();
|
||||||
|
s += "\n";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum FuzzyLevel : uint
|
||||||
|
{
|
||||||
|
FULLSTRING = 0,
|
||||||
|
SUBSTRING = 1,
|
||||||
|
PREFIX = 2,
|
||||||
|
|
||||||
|
IGNORECASE = 0x00010000,
|
||||||
|
IGNORENONSPACE = 0x00020000,
|
||||||
|
LOOSE = 0x00040000
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct ContentRestriction
|
||||||
|
{
|
||||||
|
public FuzzyLevel fuzzy;
|
||||||
|
public PropTag ulPropTag;
|
||||||
|
public PropValue* prop;
|
||||||
|
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string indent = new string(' ', depth);
|
||||||
|
string s = indent + fuzzy + ":" + ulPropTag.ToString();
|
||||||
|
s += ":" + prop->ToString();
|
||||||
|
s += "\n";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: merge with ISearch
|
||||||
|
public enum RestrictionType : UInt32
|
||||||
|
{
|
||||||
|
AND,
|
||||||
|
OR,
|
||||||
|
NOT,
|
||||||
|
CONTENT,
|
||||||
|
PROPERTY,
|
||||||
|
COMPAREPROPS,
|
||||||
|
BITMASK,
|
||||||
|
SIZE,
|
||||||
|
EXIST,
|
||||||
|
SUBRESTRICTION,
|
||||||
|
COMMENT,
|
||||||
|
COUNT,
|
||||||
|
ANNOTATION
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct SubRestriction
|
||||||
|
{
|
||||||
|
public uint cb;
|
||||||
|
public SRestriction* ptr;
|
||||||
|
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string s = "";
|
||||||
|
for (uint i = 0; i < cb; ++i)
|
||||||
|
{
|
||||||
|
s += ptr[i].ToString(depth);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct NotRestriction
|
||||||
|
{
|
||||||
|
public uint dwReserved;
|
||||||
|
public SRestriction* ptr;
|
||||||
|
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
return ptr->ToString(depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BMR : uint
|
||||||
|
{
|
||||||
|
EQZ = 0,
|
||||||
|
NEZ = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct BitMaskRestriction
|
||||||
|
{
|
||||||
|
public BMR bmr;
|
||||||
|
public PropTag prop;
|
||||||
|
public uint mask;
|
||||||
|
|
||||||
|
override public string ToString()
|
||||||
|
{
|
||||||
|
return bmr.ToString() + ":" + prop + mask.ToString("X8");
|
||||||
|
}
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string indent = new string(' ', depth);
|
||||||
|
return indent + ToString() + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe public struct ExistRestriction
|
||||||
|
{
|
||||||
|
public uint dwReserved1;
|
||||||
|
public PropTag prop;
|
||||||
|
public uint dwReserved2;
|
||||||
|
|
||||||
|
override public string ToString()
|
||||||
|
{
|
||||||
|
return prop.ToString();
|
||||||
|
}
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string indent = new string(' ', depth);
|
||||||
|
return indent + prop.ToString() + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
unsafe public struct SRestriction
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public RestrictionType rt;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public SubRestriction sub;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public NotRestriction not;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public ContentRestriction content;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public PropertyRestriction prop;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public BitMaskRestriction bitMask;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public ExistRestriction exist;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
public CommentRestriction comment;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(int depth)
|
||||||
|
{
|
||||||
|
string indent = new string(' ', depth);
|
||||||
|
string s = indent + rt.ToString() + "\n" + indent + "{\n";
|
||||||
|
switch(rt)
|
||||||
|
{
|
||||||
|
case RestrictionType.AND:
|
||||||
|
case RestrictionType.OR:
|
||||||
|
s += sub.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
case RestrictionType.NOT:
|
||||||
|
s += not.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
case RestrictionType.CONTENT:
|
||||||
|
s += content.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
case RestrictionType.PROPERTY:
|
||||||
|
s += prop.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
case RestrictionType.BITMASK:
|
||||||
|
s += bitMask.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
case RestrictionType.EXIST:
|
||||||
|
s += exist.ToString(depth + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* TODO COMPAREPROPS,
|
||||||
|
BITMASK,
|
||||||
|
SIZE,
|
||||||
|
SUBRESTRICTION,
|
||||||
|
COMMENT,
|
||||||
|
COUNT,
|
||||||
|
ANNOTATION*/
|
||||||
|
|
||||||
|
}
|
||||||
|
s += indent + "}\n";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum GetSearchCriteriaState : UInt32
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
SEARCH_RUNNING = 1,
|
||||||
|
SEARCH_REBUILD = 2,
|
||||||
|
SEARCH_RECURSIVE = 4,
|
||||||
|
SEARCH_FOREGROUND = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SetSearchCriteriaFlags : UInt32
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
STOP_SEARCH = 0x00000001,
|
||||||
|
RESTART_SEARCH = 0x00000002,
|
||||||
|
RECURSIVE_SEARCH = 0x00000004,
|
||||||
|
SHALLOW_SEARCH = 0x00000008,
|
||||||
|
FOREGROUND_SEARCH = 0x00000010,
|
||||||
|
BACKGROUND_SEARCH = 0x00000020,
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport]
|
||||||
|
[Guid("0002030B-0000-0000-C000-000000000046")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
unsafe public interface IMAPIContainer// TODO : IMAPIProp
|
||||||
|
{
|
||||||
|
// IMAPIProp
|
||||||
|
void GetLastError(Int32 hResult, UInt32 flags, out IntPtr ptr);
|
||||||
|
void SaveChanges(SaveChangesFlags flags);
|
||||||
|
void GetProps();
|
||||||
|
void GetPropList();
|
||||||
|
void OpenProperty();
|
||||||
|
void SetProps();
|
||||||
|
void DeleteProps();
|
||||||
|
void CopyTo();
|
||||||
|
void CopyProps();
|
||||||
|
void GetNamesFromIDs();
|
||||||
|
void GetIDsFromNames();
|
||||||
|
|
||||||
|
void GetContentsTable(UInt32 flags, out IntPtr table);
|
||||||
|
void GetHierarchyTable();
|
||||||
|
void OpenEntry();
|
||||||
|
void SetSearchCriteria(SRestriction* lppRestriction, SBinaryArray* lppContainerList, SetSearchCriteriaFlags flags);
|
||||||
|
void GetSearchCriteria(UInt32 flags, SRestriction** lppRestriction, SBinaryArray** lppContainerList, out GetSearchCriteriaState state);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport]
|
||||||
|
[Guid("0002030C-0000-0000-C000-000000000046")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IMAPIFolder : IMAPIContainer
|
||||||
|
{
|
||||||
|
void CreateMessage();
|
||||||
|
void CopyMessages();
|
||||||
|
void DeleteMessages();
|
||||||
|
void CreateFolder();
|
||||||
|
void CopyFolder();
|
||||||
|
void DeleteFolder();
|
||||||
|
void SetReadFlags();
|
||||||
|
void GetMessageStatus();
|
||||||
|
void SetMessageStatus();
|
||||||
|
void SaveContentsSort();
|
||||||
|
void EmptyFolder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example search code
|
||||||
|
{
|
||||||
|
MAPIFolder folder = (MAPIFolder)account.Store.GetSpecialFolder(Microsoft.Office.Interop.Outlook.OlSpecialFolders.olSpecialFolderReminders);
|
||||||
|
dynamic obj = folder.MAPIOBJECT;
|
||||||
|
IMAPIFolder imapi = obj as IMAPIFolder;
|
||||||
|
|
||||||
|
//imapi.GetSearchCriteria(0, IntPtr.Zero, IntPtr.Zero, ref state);
|
||||||
|
GetSearchCriteriaState state;
|
||||||
|
//imapi.GetContentsTable(0, out p);
|
||||||
|
SBinaryArray* sb1;
|
||||||
|
SRestriction* restrict;
|
||||||
|
imapi.GetSearchCriteria(0, &restrict, &sb1, out state);
|
||||||
|
Logger.Instance.Warning(this, "SEARCH:\n{0}", restrict->ToString());
|
||||||
|
|
||||||
|
restrict->rt = RestrictionType.AND;
|
||||||
|
imapi.SetSearchCriteria(restrict, sb1, SetSearchCriteriaFlags.NONE);
|
||||||
|
|
||||||
|
|
||||||
|
//SBinaryArray sb = Marshal.PtrToStructure<SBinaryArray>(p2);
|
||||||
|
//byte[][] ids = sb.Unmarshal();
|
||||||
|
//Logger.Instance.Warning(this, "SEARCH: {0}", StringUtil.BytesToHex(ids[0]));
|
||||||
|
//imapi.GetLastError(0, 0, out p2);
|
||||||
|
//imapi.SaveChanges(SaveChangesFlags.FORCE_SAVE);
|
||||||
|
} */
|
||||||
|
}
|
@ -83,6 +83,8 @@ namespace Acacia
|
|||||||
|
|
||||||
public const string PR_SUBJECT = PROP + "0037" + PT_UNICODE;
|
public const string PR_SUBJECT = PROP + "0037" + PT_UNICODE;
|
||||||
|
|
||||||
|
public const string PR_CONTAINER_CLASS = PROP + "3613" + PT_UNICODE;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Email specific
|
#region Email specific
|
||||||
@ -120,6 +122,7 @@ namespace Acacia
|
|||||||
public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG;
|
public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG;
|
||||||
public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN;
|
public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN;
|
||||||
public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG;
|
public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG;
|
||||||
|
public const string PR_EAS_NAME = PROP + "6915" + PT_UNICODE;
|
||||||
|
|
||||||
public enum SyncType
|
public enum SyncType
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,24 @@ namespace Acacia.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The password for account '{0}' is not available. Advanced Z-Push features will not work..
|
||||||
|
/// </summary>
|
||||||
|
internal static string AccountNoPassword_Body {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountNoPassword_Body", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Password unavailable.
|
||||||
|
/// </summary>
|
||||||
|
internal static string AccountNoPassword_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AccountNoPassword_Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Support.
|
/// Looks up a localized string similar to Support.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -785,6 +803,24 @@ namespace Acacia.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to To synchronise the contacts folder '{0}', Outlook must be restarted. Click 'Yes' to restart Outlook now, or 'No' if you plan to restart Outlook later..
|
||||||
|
/// </summary>
|
||||||
|
internal static string SecondaryContactsPatched_Body {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SecondaryContactsPatched_Body", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Contacts folder.
|
||||||
|
/// </summary>
|
||||||
|
internal static string SecondaryContactsPatched_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SecondaryContactsPatched_Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Unable to open the shared folder. Please ensure you have permission to open the shared folder..
|
/// Looks up a localized string similar to Unable to open the shared folder. Please ensure you have permission to open the shared folder..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -431,4 +431,18 @@
|
|||||||
<data name="Ribbon_About_Supertip" xml:space="preserve">
|
<data name="Ribbon_About_Supertip" xml:space="preserve">
|
||||||
<value>Shows the about dialog, which contains licensing and version information.</value>
|
<value>Shows the about dialog, which contains licensing and version information.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SecondaryContactsPatched_Body" xml:space="preserve">
|
||||||
|
<value>To synchronise the contacts folder '{0}', Outlook must be restarted. Click 'Yes' to restart Outlook now, or 'No' if you plan to restart Outlook later.</value>
|
||||||
|
<comment>Shown when a secondary contact folder is detected, to inform the user that a restart is required</comment>
|
||||||
|
</data>
|
||||||
|
<data name="SecondaryContactsPatched_Title" xml:space="preserve">
|
||||||
|
<value>Contacts folder</value>
|
||||||
|
<comment>Shown when a secondary contact folder is detected, to inform the user that a restart is required</comment>
|
||||||
|
</data>
|
||||||
|
<data name="AccountNoPassword_Body" xml:space="preserve">
|
||||||
|
<value>The password for account '{0}' is not available. Advanced Z-Push features will not work.</value>
|
||||||
|
</data>
|
||||||
|
<data name="AccountNoPassword_Title" xml:space="preserve">
|
||||||
|
<value>Password unavailable</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
71
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Enums.cs
Normal file
71
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Enums.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/// Copyright 2017 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
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AccountType
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
EAS,
|
||||||
|
Other
|
||||||
|
}
|
||||||
|
}
|
53
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs
Normal file
53
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/// Copyright 2017 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.Security;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface IAccount : IDisposable
|
||||||
|
{
|
||||||
|
AccountType AccountType { get; }
|
||||||
|
|
||||||
|
IStore Store { get; }
|
||||||
|
|
||||||
|
void SendReceive();
|
||||||
|
|
||||||
|
string DisplayName { get; }
|
||||||
|
|
||||||
|
string SmtpAddress { get; }
|
||||||
|
|
||||||
|
string UserName { get; }
|
||||||
|
|
||||||
|
string ServerURL { get; }
|
||||||
|
|
||||||
|
string DeviceId { get; }
|
||||||
|
|
||||||
|
SecureString Password { get; }
|
||||||
|
|
||||||
|
bool HasPassword { get; }
|
||||||
|
|
||||||
|
string StoreID { get; }
|
||||||
|
|
||||||
|
string DomainName { get; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
90
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs
Normal file
90
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Features;
|
||||||
|
using Acacia.UI.Outlook;
|
||||||
|
using Acacia.Utils;
|
||||||
|
using Acacia.ZPush;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using NSOutlookDelegates = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface IAddIn
|
||||||
|
{
|
||||||
|
ZPushWatcher Watcher { get; }
|
||||||
|
MailEvents MailEvents { get; }
|
||||||
|
IEnumerable<Feature> Features { get; }
|
||||||
|
IEnumerable<KeyValuePair<string,string>> COMAddIns { get; }
|
||||||
|
string Version { get; }
|
||||||
|
ISyncObject GetSyncObject();
|
||||||
|
|
||||||
|
#region UI
|
||||||
|
|
||||||
|
OutlookUI OutlookUI { get; }
|
||||||
|
IWin32Window Window { get; }
|
||||||
|
IExplorer GetActiveExplorer();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Event handlers
|
||||||
|
|
||||||
|
// TODO: custom event types
|
||||||
|
event NSOutlookDelegates.ApplicationEvents_11_ItemLoadEventHandler ItemLoad;
|
||||||
|
event NSOutlookDelegates.ApplicationEvents_11_ItemSendEventHandler ItemSend;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Miscellaneous methods
|
||||||
|
// TODO: clean this up
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends and receives all accounts, or a specific account.
|
||||||
|
/// </summary>
|
||||||
|
void SendReceive(IAccount account = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restarts the application
|
||||||
|
/// </summary>
|
||||||
|
void Restart();
|
||||||
|
void Quit();
|
||||||
|
|
||||||
|
void InvokeUI(Action action);
|
||||||
|
|
||||||
|
IFolder GetFolderFromID(string folderId);
|
||||||
|
|
||||||
|
FeatureType GetFeature<FeatureType>()
|
||||||
|
where FeatureType : Feature;
|
||||||
|
|
||||||
|
IRecipient ResolveRecipient(string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the store manager. This is a shared object and must NOT be disposed.
|
||||||
|
/// </summary>
|
||||||
|
IStores Stores
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -29,5 +29,6 @@ namespace Acacia.Stubs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
|
new IAddressBook Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
/// Copyright 2017 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -22,17 +22,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Acacia.Stubs
|
namespace Acacia.Stubs
|
||||||
{
|
{
|
||||||
public interface IUserProperty<Type>
|
public interface IAddressEntry : IComWrapper
|
||||||
{
|
{
|
||||||
#region Properties
|
|
||||||
|
|
||||||
Type Value
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -22,9 +22,9 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Acacia.Stubs
|
namespace Acacia.Stubs
|
||||||
{
|
{
|
||||||
public interface IBase : IDisposable
|
public interface IBase : IComWrapper
|
||||||
{
|
{
|
||||||
#region MAPI properties
|
#region Properties
|
||||||
|
|
||||||
bool AttrHidden { get; set; }
|
bool AttrHidden { get; set; }
|
||||||
|
|
||||||
@ -34,23 +34,35 @@ namespace Acacia.Stubs
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
string EntryId { get; }
|
#region Ids and hierarchy
|
||||||
IFolder Parent { get; }
|
|
||||||
string ParentEntryId { get; }
|
string EntryID { get; }
|
||||||
|
IFolder Parent { get; }
|
||||||
|
string ParentEntryID { get; }
|
||||||
|
|
||||||
IStore Store { get; }
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Quick accessor to Store.Id, to prevent allocation a wrapper for it.
|
/// Returns the store. The owner is responsible for disposing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string StoreId { get; }
|
IStore GetStore();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Quick accessor to Store.DisplayName, to prevent allocation a wrapper for it.
|
/// Quick accessor to Store.Id, to prevent allocating a wrapper for it.
|
||||||
|
/// </summary>
|
||||||
|
string StoreID { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Quick accessor to Store.DisplayName, to prevent allocating a wrapper for it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string StoreDisplayName { get; }
|
string StoreDisplayName { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
void Delete();
|
void Delete();
|
||||||
|
|
||||||
bool MustRelease { get; set; }
|
|
||||||
|
|
||||||
string ToString();
|
string ToString();
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
28
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IComWrapper.cs
Normal file
28
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IComWrapper.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/// Copyright 2017 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 interface IComWrapper : IDisposable
|
||||||
|
{
|
||||||
|
bool MustRelease { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/// Copyright 2017 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.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface IMSOCommand
|
||||||
|
{
|
||||||
|
Bitmap GetImage(Size imageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICommandBars : IComWrapper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the command with the specified id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The id.</param>
|
||||||
|
/// <returns>The command, or null if it does not exist.</returns>
|
||||||
|
IMSOCommand GetMso(string id);
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,11 @@ namespace Acacia.Stubs
|
|||||||
string DLName { get; set; }
|
string DLName { get; set; }
|
||||||
string SMTPAddress { get; set; }
|
string SMTPAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a member to the distribution list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item. This is not disposed or released.</param>
|
||||||
|
/// <exception cref="NotSupportedException">If the item is not a contact or distribution list</exception>
|
||||||
void AddMember(IItem item);
|
void AddMember(IItem item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
46
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs
Normal file
46
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IExplorer.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/// Copyright 2017 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;
|
||||||
|
using NSOutlookDelegates = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface IExplorer : IOutlookWindow
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the command bars.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The command bars. The caller is responsible for disposing.</returns>
|
||||||
|
ICommandBars GetCommandBars();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the currently selected folder, or null if no folder is selected.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The folder. The caller is responsible for disposing.</returns>
|
||||||
|
IFolder GetCurrentFolder();
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
// TODO: custom delegates
|
||||||
|
event NSOutlookDelegates.ExplorerEvents_10_SelectionChangeEventHandler SelectionChange;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -35,12 +35,14 @@ namespace Acacia.Stubs
|
|||||||
|
|
||||||
bool ShowAsOutlookAB { get; set; }
|
bool ShowAsOutlookAB { get; set; }
|
||||||
|
|
||||||
IEnumerable<IItem> Items { get; }
|
IItems Items { get; }
|
||||||
|
|
||||||
IEnumerable<IItem> ItemsSorted(string field, bool descending);
|
|
||||||
|
|
||||||
IItem GetItemById(string id);
|
IItem GetItemById(string id);
|
||||||
|
|
||||||
|
string FullFolderPath { get; }
|
||||||
|
|
||||||
|
ItemType DefaultItemType { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Searching
|
#region Searching
|
||||||
@ -55,6 +57,11 @@ namespace Acacia.Stubs
|
|||||||
IEnumerable<FolderType> GetSubFolders<FolderType>()
|
IEnumerable<FolderType> GetSubFolders<FolderType>()
|
||||||
where FolderType : IFolder;
|
where FolderType : IFolder;
|
||||||
|
|
||||||
|
IFolders SubFolders
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
|
||||||
FolderType GetSubFolder<FolderType>(string name)
|
FolderType GetSubFolder<FolderType>(string name)
|
||||||
where FolderType : IFolder;
|
where FolderType : IFolder;
|
||||||
|
|
||||||
@ -101,5 +108,11 @@ namespace Acacia.Stubs
|
|||||||
/// function prevents creating lots of wrappers.
|
/// function prevents creating lots of wrappers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsAtDepth(int depth);
|
bool IsAtDepth(int depth);
|
||||||
|
|
||||||
|
// TODO: remove this. It's a quick hack to find the events associated with this folder for ZPushWatcher.
|
||||||
|
// make event watching part of the folder instead
|
||||||
|
ZPushFolder ZPush { get; set; }
|
||||||
|
|
||||||
|
IFolder Clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolders.cs
Normal file
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolders.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/// Copyright 2017 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 delegate void IFolders_FolderEventHandler(IFolder folder);
|
||||||
|
public delegate void IFolders_EventHandler();
|
||||||
|
|
||||||
|
public interface IFolders_Events : IDisposable
|
||||||
|
{
|
||||||
|
event IFolders_FolderEventHandler FolderAdd;
|
||||||
|
event IFolders_FolderEventHandler FolderChange;
|
||||||
|
event IFolders_EventHandler FolderRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IFolders : IEnumerable<IFolder>
|
||||||
|
{
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an events subscribption object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The events. The caller is responsible for disposing</returns>
|
||||||
|
IFolders_Events GetEvents();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -34,16 +34,31 @@ namespace Acacia.Stubs
|
|||||||
string Body { get; set; }
|
string Body { get; set; }
|
||||||
string Subject { get; set; }
|
string Subject { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the events for the item. The caller is responsible for disposing.
|
||||||
|
/// </summary>
|
||||||
|
IItemEvents GetEvents();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region User properties
|
#region User properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the user property with the specified name.
|
/// Retrieves the item's user property with the specified name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="create">If true, the property is created if it does not exist.
|
/// <typeparam name="Type">The property type.</typeparam>
|
||||||
/// If false, null is returned in this case</param>
|
/// <param name="name">The name of the property.</param>
|
||||||
IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false);
|
/// <returns>The property's value, if it exists. If it does not exist, the type's default value is returned.
|
||||||
|
/// A nullable type can be specified to return null if the property does not exist.</returns>
|
||||||
|
Type GetUserProperty<Type>(string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the property.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="Type">The property type</typeparam>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
void SetUserProperty<Type>(string name, Type value);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
60
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItemEvents.cs
Normal file
60
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItemEvents.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/// Copyright 2017 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;
|
||||||
|
using NSOutlookDelegates = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface IItemEvents : IComWrapper
|
||||||
|
{
|
||||||
|
#region Event handlers
|
||||||
|
|
||||||
|
// TODO: custom delegates
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_AfterWriteEventHandler AfterWrite;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_AttachmentAddEventHandler AttachmentAdd;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_AttachmentReadEventHandler AttachmentRead;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_AttachmentRemoveEventHandler AttachmentRemove;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAttachmentAddEventHandler BeforeAttachmentAdd;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAttachmentPreviewEventHandler BeforeAttachmentPreview;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAttachmentReadEventHandler BeforeAttachmentRead;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAttachmentSaveEventHandler BeforeAttachmentSave;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAttachmentWriteToTempFileEventHandler BeforeAttachmentWriteToTempFile;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeAutoSaveEventHandler BeforeAutoSave;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeCheckNamesEventHandler BeforeCheckNames;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeDeleteEventHandler BeforeDelete;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_BeforeReadEventHandler BeforeRead;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_CloseEventHandler Close;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_CustomActionEventHandler CustomAction;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_CustomPropertyChangeEventHandler CustomPropertyChange;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_ForwardEventHandler Forward;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_OpenEventHandler Open;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_PropertyChangeEventHandler PropertyChange;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_ReadEventHandler Read;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_ReadCompleteEventHandler ReadComplete;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_ReplyEventHandler Reply;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_ReplyAllEventHandler ReplyAll;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_SendEventHandler Send;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_UnloadEventHandler Unload;
|
||||||
|
event NSOutlookDelegates.ItemEvents_10_WriteEventHandler Write;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
56
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItems.cs
Normal file
56
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IItems.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/// Copyright 2017 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 delegate void IItems_ItemEventHandler(IItem item);
|
||||||
|
|
||||||
|
|
||||||
|
public interface IItems_Events : IDisposable
|
||||||
|
{
|
||||||
|
event IItems_ItemEventHandler ItemAdd;
|
||||||
|
event IItems_ItemEventHandler ItemChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IItems : IEnumerable<IItem>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts the items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field"></param>
|
||||||
|
/// <param name="descending"></param>
|
||||||
|
/// <returns>The current collection, which will be sorted</returns>
|
||||||
|
IItems Sort(string field, bool descending);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Filters the items for a specific type.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An enumerable for items of the specified type.</returns>
|
||||||
|
IEnumerable<T> Typed<T>() where T : IItem;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an events subscribption object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The events. The caller is responsible for disposing</returns>
|
||||||
|
IItems_Events GetEvents();
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
|
|
||||||
namespace Acacia.Stubs
|
namespace Acacia.Stubs
|
||||||
{
|
{
|
||||||
@ -34,6 +33,10 @@ namespace Acacia.Stubs
|
|||||||
string SenderEmailAddress { get; }
|
string SenderEmailAddress { get; }
|
||||||
string SenderName { get; }
|
string SenderName { get; }
|
||||||
|
|
||||||
void SetSender(AddressEntry addressEntry);
|
/// <summary>
|
||||||
|
/// Sets the sender.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="addressEntry">The address. The caller is responsible for disposing.</param>
|
||||||
|
void SetSender(IAddressEntry addressEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
/// Copyright 2017 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -22,17 +22,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Acacia.Stubs
|
namespace Acacia.Stubs
|
||||||
{
|
{
|
||||||
public enum ItemType
|
public interface IOutlookWindow : IComWrapper
|
||||||
{
|
{
|
||||||
MailItem = 0,
|
|
||||||
AppointmentItem = 1,
|
|
||||||
ContactItem = 2,
|
|
||||||
TaskItem = 3,
|
|
||||||
JournalItem = 4,
|
|
||||||
NoteItem = 5,
|
|
||||||
PostItem = 6,
|
|
||||||
DistributionListItem = 7,
|
|
||||||
MobileItemSMS = 11,
|
|
||||||
MobileItemMMS = 12
|
|
||||||
}
|
}
|
||||||
}
|
}
|
37
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IRecipient.cs
Normal file
37
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IRecipient.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/// Copyright 2017 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 interface IRecipient : IComWrapper
|
||||||
|
{
|
||||||
|
bool IsResolved { get; }
|
||||||
|
|
||||||
|
string Name { get; }
|
||||||
|
string Address { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the address entry. The caller is responsible for disposing it.
|
||||||
|
/// </summary>
|
||||||
|
IAddressEntry GetAddressEntry();
|
||||||
|
}
|
||||||
|
}
|
@ -22,14 +22,17 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Acacia.Stubs
|
namespace Acacia.Stubs
|
||||||
{
|
{
|
||||||
public enum SearchOperation
|
/// <summary>
|
||||||
|
/// Order matches MAPI RELOP_ constants
|
||||||
|
/// </summary>
|
||||||
|
public enum SearchOperation : uint
|
||||||
{
|
{
|
||||||
|
Smaller,
|
||||||
|
SmallerEqual,
|
||||||
|
Greater,
|
||||||
|
GreaterEqual,
|
||||||
Equal,
|
Equal,
|
||||||
NotEqual,
|
NotEqual,
|
||||||
SmallerEqual,
|
|
||||||
Smaller,
|
|
||||||
GreaterEqual,
|
|
||||||
Greater,
|
|
||||||
Like
|
Like
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +44,8 @@ namespace Acacia.Stubs
|
|||||||
public enum SearchOperator
|
public enum SearchOperator
|
||||||
{
|
{
|
||||||
Or,
|
Or,
|
||||||
And
|
And,
|
||||||
|
Not
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISearchOperator
|
public interface ISearchOperator
|
||||||
@ -49,8 +53,7 @@ namespace Acacia.Stubs
|
|||||||
ISearchField AddField(string name, bool isUserField = false);
|
ISearchField AddField(string name, bool isUserField = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISearch<ItemType>
|
public interface ISearch<ItemType> : ISearchOperator, IDisposable
|
||||||
: ISearchOperator
|
|
||||||
where ItemType : IItem
|
where ItemType : IItem
|
||||||
{
|
{
|
||||||
ISearchOperator AddOperator(SearchOperator oper);
|
ISearchOperator AddOperator(SearchOperator oper);
|
||||||
|
@ -24,9 +24,29 @@ namespace Acacia.Stubs
|
|||||||
{
|
{
|
||||||
public interface IStore : IDisposable
|
public interface IStore : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the root folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <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; }
|
||||||
|
|
||||||
|
bool IsFileStore { get; }
|
||||||
|
string FilePath { get; }
|
||||||
|
|
||||||
|
void EmptyDeletedItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStores.cs
Normal file
48
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStores.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/// Copyright 2017 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 delegate void IStores_AccountDiscovered(IAccount account);
|
||||||
|
public delegate void IStores_AccountRemoved(IAccount account);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the stores and associated acounts.
|
||||||
|
/// </summary>
|
||||||
|
public interface IStores: IComWrapper, IEnumerable<IStore>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the accounts. The accounts are shared objects and must not be disposed.
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<IAccount> Accounts { get; }
|
||||||
|
|
||||||
|
event IStores_AccountDiscovered AccountDiscovered;
|
||||||
|
event IStores_AccountRemoved AccountRemoved;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a file store to the current collection. If the store is already in the collection, an exception is thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path.</param>
|
||||||
|
/// <returns>The store. The caller is responsible for disposing.</returns>
|
||||||
|
IStore AddFileStore(string path);
|
||||||
|
}
|
||||||
|
}
|
50
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISyncObject.cs
Normal file
50
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/ISyncObject.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/// Copyright 2017 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;
|
||||||
|
using NSOutlookDelegates = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs
|
||||||
|
{
|
||||||
|
public interface ISyncObject : IComWrapper
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
// TODO: custom delegates
|
||||||
|
event NSOutlookDelegates.SyncObjectEvents_OnErrorEventHandler OnError;
|
||||||
|
event NSOutlookDelegates.SyncObjectEvents_ProgressEventHandler Progress;
|
||||||
|
event NSOutlookDelegates.SyncObjectEvents_SyncEndEventHandler SyncEnd;
|
||||||
|
event NSOutlookDelegates.SyncObjectEvents_SyncStartEventHandler SyncStart;
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
[TypeConverter(typeof(ExpandableObjectConverter))]
|
||||||
|
class AccountWrapper : DisposableWrapper, IAccount, LogContext
|
||||||
|
{
|
||||||
|
private readonly string _regPath;
|
||||||
|
private readonly IStore _store;
|
||||||
|
|
||||||
|
internal AccountWrapper(string regPath, IStore store)
|
||||||
|
{
|
||||||
|
this._regPath = regPath;
|
||||||
|
this._store = store;
|
||||||
|
|
||||||
|
// Cache the SmtpAddress, it is used as the key
|
||||||
|
SmtpAddress = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EMAIL, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
_store.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public string LogContextId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "ZPushAccount(" + SmtpAddress + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return SmtpAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers an Outlook send/receive operation for this account.
|
||||||
|
/// </summary>
|
||||||
|
public void SendReceive()
|
||||||
|
{
|
||||||
|
ThisAddIn.Instance.SendReceive(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public AccountType AccountType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (DeviceId == null) ? AccountType.Other : AccountType.EAS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public IStore Store
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_DISPLAYNAME, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SmtpAddress
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string UserName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_USERNAME, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ServerURL
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_SERVER, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DeviceId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_DEVICEID, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public SecureString Password
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
byte[] encrypted = (byte[])Registry.GetValue(_regPath, OutlookConstants.REG_VAL_EAS_PASSWORD, null);
|
||||||
|
return PasswordEncryption.Decrypt(encrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public bool HasPassword
|
||||||
|
{
|
||||||
|
get { return Registry.GetValue(_regPath, OutlookConstants.REG_VAL_EAS_PASSWORD, null) != null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get { return GetStoreId(_regPath); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetStoreId(string regPath)
|
||||||
|
{
|
||||||
|
return StringUtil.BytesToHex((byte[])Registry.GetValue(regPath, OutlookConstants.REG_VAL_EAS_STOREID, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DomainName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int index = SmtpAddress.IndexOf('@');
|
||||||
|
if (index < 0)
|
||||||
|
return SmtpAddress;
|
||||||
|
else
|
||||||
|
return SmtpAddress.Substring(index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,257 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Features;
|
||||||
|
using Acacia.Native;
|
||||||
|
using Acacia.UI.Outlook;
|
||||||
|
using Acacia.Utils;
|
||||||
|
using Acacia.ZPush;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
public class AddInWrapper : IAddIn
|
||||||
|
{
|
||||||
|
private readonly NSOutlook.Application _app;
|
||||||
|
private readonly ThisAddIn _thisAddIn;
|
||||||
|
private readonly StoresWrapper _stores;
|
||||||
|
|
||||||
|
public AddInWrapper(ThisAddIn thisAddIn)
|
||||||
|
{
|
||||||
|
this._thisAddIn = thisAddIn;
|
||||||
|
this._app = thisAddIn.Application;
|
||||||
|
|
||||||
|
NSOutlook.NameSpace session = _app.Session;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this._stores = new StoresWrapper(session.Stores);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendReceive(IAccount account)
|
||||||
|
{
|
||||||
|
// TODO: send/receive specific account
|
||||||
|
NSOutlook.NameSpace session = _app.Session;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
session.SendAndReceive(false);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_stores.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Restart()
|
||||||
|
{
|
||||||
|
// Can not use the assembly location, as that is in the GAC
|
||||||
|
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
|
||||||
|
UriBuilder uri = new UriBuilder(codeBase);
|
||||||
|
string path = Uri.UnescapeDataString(uri.Path);
|
||||||
|
// Create the path to the restarter
|
||||||
|
path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(path), "OutlookRestarter.exe");
|
||||||
|
|
||||||
|
// Run that
|
||||||
|
Process process = new Process();
|
||||||
|
process.StartInfo = new ProcessStartInfo(path, Environment.CommandLine);
|
||||||
|
process.Start();
|
||||||
|
|
||||||
|
// And close us
|
||||||
|
_app.Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Quit()
|
||||||
|
{
|
||||||
|
_app.Quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ApplicationEvents_11_ItemLoadEventHandler ItemLoad
|
||||||
|
{
|
||||||
|
add { _app.ItemLoad += value; }
|
||||||
|
remove { _app.ItemLoad -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ApplicationEvents_11_ItemSendEventHandler ItemSend
|
||||||
|
{
|
||||||
|
add { _app.ItemSend += value; }
|
||||||
|
remove { _app.ItemSend -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISyncObject GetSyncObject()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.NameSpace session = com.Add(_app.Session);
|
||||||
|
NSOutlook.SyncObjects syncObjects = com.Add(session.SyncObjects);
|
||||||
|
return new SyncObjectWrapper(syncObjects.AppFolders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region UI
|
||||||
|
|
||||||
|
public OutlookUI OutlookUI { get { return _thisAddIn.OutlookUI; } }
|
||||||
|
|
||||||
|
public IExplorer GetActiveExplorer()
|
||||||
|
{
|
||||||
|
return new ExplorerWrapper(_app.ActiveExplorer());
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Window handle
|
||||||
|
|
||||||
|
private class WindowHandle : IWin32Window
|
||||||
|
{
|
||||||
|
private IntPtr hWnd;
|
||||||
|
|
||||||
|
public WindowHandle(IntPtr hWnd)
|
||||||
|
{
|
||||||
|
this.hWnd = hWnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Handle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return hWnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWin32Window Window
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IOleWindow win = _app.ActiveWindow() as IOleWindow;
|
||||||
|
if (win == null)
|
||||||
|
return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IntPtr hWnd;
|
||||||
|
win.GetWindow(out hWnd);
|
||||||
|
return new WindowHandle(hWnd);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(win);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public ZPushWatcher Watcher { get { return _thisAddIn.Watcher; } }
|
||||||
|
public MailEvents MailEvents { get { return _thisAddIn.MailEvents; } }
|
||||||
|
public IEnumerable<Feature> Features { get { return _thisAddIn.Features; } }
|
||||||
|
public IEnumerable<KeyValuePair<string, string>> COMAddIns
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Microsoft.Office.Core.COMAddIns addIns = _app.COMAddIns;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (Microsoft.Office.Core.COMAddIn comAddin in addIns)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
yield return new KeyValuePair<string, string>(comAddin.ProgId, comAddin.Description);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(comAddin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(addIns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
get { return _app.Version; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FeatureType GetFeature<FeatureType>()
|
||||||
|
where FeatureType : Feature
|
||||||
|
{
|
||||||
|
foreach (Feature feature in Features)
|
||||||
|
{
|
||||||
|
if (feature is FeatureType)
|
||||||
|
return (FeatureType)feature;
|
||||||
|
}
|
||||||
|
return default(FeatureType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void InvokeUI(Action action)
|
||||||
|
{
|
||||||
|
// [ZP-992] For some reason using the dispatcher causes a deadlock
|
||||||
|
// since switching to UI-chunked tasks. Running directly works.
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFolder GetFolderFromID(string folderId)
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.NameSpace nmspace = com.Add(_app.Session);
|
||||||
|
NSOutlook.Folder f = (NSOutlook.Folder)nmspace.GetFolderFromID(folderId);
|
||||||
|
return Mapping.Wrap<IFolder>(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IRecipient ResolveRecipient(string name)
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.NameSpace session = com.Add(_app.Session);
|
||||||
|
// Add recipient, unlock after Resolve (which might throw) to wrap
|
||||||
|
NSOutlook.Recipient recipient = com.Add(session.CreateRecipient(name));
|
||||||
|
if (recipient == null)
|
||||||
|
return null;
|
||||||
|
recipient.Resolve();
|
||||||
|
return Mapping.Wrap(com.Remove(recipient));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStores Stores
|
||||||
|
{
|
||||||
|
get { return _stores; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,30 +15,39 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class AddressBookWrapper : FolderWrapper, IAddressBook
|
class AddressBookWrapper : FolderWrapper, IAddressBook
|
||||||
{
|
{
|
||||||
public AddressBookWrapper(Folder folder)
|
public AddressBookWrapper(NSOutlook.MAPIFolder folder)
|
||||||
:
|
:
|
||||||
base(folder)
|
base(folder)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IFolder Clone()
|
||||||
|
{
|
||||||
|
return new AddressBookWrapper(CloneComObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
IAddressBook IAddressBook.Clone()
|
||||||
|
{
|
||||||
|
return new AddressBookWrapper(CloneComObject());
|
||||||
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
foreach(dynamic item in _item.Items)
|
foreach(dynamic item in _item.Items.ComEnum())
|
||||||
{
|
{
|
||||||
item.Delete();
|
item.Delete();
|
||||||
ComRelease.Release(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
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.OutlookWrappers
|
||||||
|
{
|
||||||
|
class AddressEntryWrapper : ComWrapper<NSOutlook.AddressEntry>, IAddressEntry
|
||||||
|
{
|
||||||
|
internal AddressEntryWrapper(NSOutlook.AddressEntry item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal NSOutlook.AddressEntry RawItem { get { return _item; } }
|
||||||
|
}
|
||||||
|
}
|
@ -19,27 +19,21 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class AppointmentItemWrapper : OutlookWrapper<AppointmentItem>, IAppointmentItem, IZPushItem
|
class AppointmentItemWrapper : OutlookItemWrapper<NSOutlook.AppointmentItem>, IAppointmentItem, IZPushItem
|
||||||
{
|
{
|
||||||
|
|
||||||
internal AppointmentItemWrapper(AppointmentItem item)
|
internal AppointmentItemWrapper(NSOutlook.AppointmentItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public override string ToString() { return "Appointment: " + Subject; }
|
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region IAppointmentItem implementation
|
||||||
{
|
|
||||||
return _item.PropertyAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
|
|
||||||
public DateTime Start
|
public DateTime Start
|
||||||
{
|
{
|
||||||
@ -58,6 +52,29 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Location = value; }
|
set { _item.Location = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
return _item.UserProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
|
{
|
||||||
|
return _item.PropertyAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Appointment:" + Subject;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
get { return _item.Body; }
|
get { return _item.Body; }
|
||||||
@ -70,45 +87,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Subject = value; }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
|
||||||
// TODO: release needed
|
|
||||||
public string StoreId { get { return _item.Parent?.Store?.StoreID; } }
|
|
||||||
public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreDisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/// 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 Acacia.Features.DebugSupport;
|
||||||
|
using Acacia.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
abstract class ComWrapper<ItemType> : DisposableWrapper, IComWrapper
|
||||||
|
{
|
||||||
|
protected readonly ItemType _item;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a wrapper.
|
||||||
|
/// </summary>
|
||||||
|
protected ComWrapper(ItemType item)
|
||||||
|
{
|
||||||
|
this._item = item;
|
||||||
|
MustRelease = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MustRelease
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected void DoRelease()
|
||||||
|
{
|
||||||
|
if (MustRelease)
|
||||||
|
{
|
||||||
|
ComRelease.Release(_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NSOffice = Microsoft.Office.Core;
|
||||||
|
using System.Drawing;
|
||||||
|
using stdole;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class CommandBarsWrapper : ComWrapper<NSOffice.CommandBars>, ICommandBars
|
||||||
|
{
|
||||||
|
private class MSOCommand : IMSOCommand
|
||||||
|
{
|
||||||
|
private readonly CommandBarsWrapper _commands;
|
||||||
|
private readonly string _id;
|
||||||
|
|
||||||
|
public MSOCommand(CommandBarsWrapper commands, string id)
|
||||||
|
{
|
||||||
|
this._commands = commands;
|
||||||
|
this._id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap GetImage(Size imageSize)
|
||||||
|
{
|
||||||
|
IPictureDisp pict = _commands._item.GetImageMso(_id, imageSize.Width, imageSize.Height);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ImageUtils.GetBitmapFromHBitmap(new IntPtr(pict.Handle));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(pict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBarsWrapper(NSOffice.CommandBars item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMSOCommand GetMso(string id)
|
||||||
|
{
|
||||||
|
return new MSOCommand(this, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,30 +15,23 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class ContactItemWrapper : OutlookWrapper<ContactItem>, IContactItem
|
class ContactItemWrapper : OutlookItemWrapper<NSOutlook.ContactItem>, IContactItem
|
||||||
{
|
{
|
||||||
internal ContactItemWrapper(ContactItem item)
|
internal ContactItemWrapper(NSOutlook.ContactItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
|
||||||
{
|
|
||||||
return _item.PropertyAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() { return "Contact: " + Subject; }
|
|
||||||
|
|
||||||
#region IContactItem implementation
|
#region IContactItem implementation
|
||||||
|
|
||||||
public string CustomerID
|
public string CustomerID
|
||||||
@ -179,6 +172,30 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Language = value; }
|
set { _item.Language = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetPicture(string path)
|
||||||
|
{
|
||||||
|
_item.AddPicture(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
return _item.UserProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
|
{
|
||||||
|
return _item.PropertyAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Contact:" + Subject;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IItem implementation
|
#region IItem implementation
|
||||||
@ -195,49 +212,71 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Subject = value; }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
|
||||||
// TODO: release needed
|
|
||||||
public string StoreId { get { return _item.Parent?.Store?.StoreID; } }
|
|
||||||
public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } }
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
public void SetPicture(string path)
|
|
||||||
{
|
|
||||||
_item.AddPicture(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IBase implementation
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreDisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -19,48 +19,33 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class DistributionListWrapper : OutlookWrapper<DistListItem>, IDistributionList
|
class DistributionListWrapper : OutlookItemWrapper<NSOutlook.DistListItem>, IDistributionList
|
||||||
{
|
{
|
||||||
internal DistributionListWrapper(DistListItem item)
|
internal DistributionListWrapper(NSOutlook.DistListItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region IDistributionList implementation
|
||||||
{
|
|
||||||
return _item.PropertyAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
|
|
||||||
public string SMTPAddress
|
public string SMTPAddress
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
PropertyAccessor props = _item.PropertyAccessor;
|
return (string)GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS);
|
||||||
try
|
|
||||||
{
|
|
||||||
return (string)props.GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(props);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
string displayName = DLName + " (" + value + ")";
|
string displayName = DLName + " (" + value + ")";
|
||||||
byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value);
|
byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value);
|
||||||
PropertyAccessor props = _item.PropertyAccessor;
|
|
||||||
try
|
SetProperties(
|
||||||
{
|
|
||||||
props.SetProperties(
|
|
||||||
new string[]
|
new string[]
|
||||||
{
|
{
|
||||||
OutlookConstants.PR_EMAIL1DISPLAYNAME,
|
OutlookConstants.PR_EMAIL1DISPLAYNAME,
|
||||||
@ -79,35 +64,19 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string DLName
|
||||||
{
|
{
|
||||||
ComRelease.Release(props);
|
get { return _item.DLName; }
|
||||||
|
set { _item.DLName = value; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
|
||||||
|
|
||||||
public void AddMember(IItem item)
|
public void AddMember(IItem item)
|
||||||
{
|
{
|
||||||
if (item is IContactItem)
|
if (item is IContactItem)
|
||||||
{
|
{
|
||||||
string email = ((IContactItem)item).Email1Address;
|
AddContactMember((IContactItem)item);
|
||||||
Recipient recipient = ThisAddIn.Instance.Application.Session.CreateRecipient(email);
|
|
||||||
if (recipient.Resolve())
|
|
||||||
_item.AddMember(recipient);
|
|
||||||
else
|
|
||||||
Logger.Instance.Warning(this, "Unable to resolve recipient: {0}", email);
|
|
||||||
}
|
}
|
||||||
else if (item is IDistributionList)
|
else if (item is IDistributionList)
|
||||||
{
|
{
|
||||||
@ -115,7 +84,21 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Instance.Warning(this, "Unknown item type when adding to distlist: {0}", item);
|
throw new NotSupportedException("Unknown item type when adding to distlist: " + item.GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddContactMember(IContactItem member)
|
||||||
|
{
|
||||||
|
string email = member.Email1Address;
|
||||||
|
using (IRecipient recipient = ThisAddIn.Instance.ResolveRecipient(email))
|
||||||
|
{
|
||||||
|
if (recipient.IsResolved)
|
||||||
|
{
|
||||||
|
_item.AddMember(((RecipientWrapper)recipient).RawItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Logger.Instance.Warning(this, "Unable to resolve recipient: {0}", email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,9 +107,8 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
// Resolving a distribution list can only be done by name. This fails if the name is in multiple
|
// Resolving a distribution list can only be done by name. This fails if the name is in multiple
|
||||||
// groups (e.g. 'Germany' and 'Sales Germany' fails to find Germany). Patch the member
|
// groups (e.g. 'Germany' and 'Sales Germany' fails to find Germany). Patch the member
|
||||||
// tables explicitly.
|
// tables explicitly.
|
||||||
PropertyAccessor props = _item.PropertyAccessor;
|
object[] members = (object[])GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS);
|
||||||
object[] members = props.GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS);
|
object[] oneOffMembers = (object[])GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS);
|
||||||
object[] oneOffMembers = props.GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS);
|
|
||||||
|
|
||||||
// Create the new member ids
|
// Create the new member ids
|
||||||
byte[] memberId = CreateMemberId(member);
|
byte[] memberId = CreateMemberId(member);
|
||||||
@ -163,7 +145,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
newOneOffMembers[existingIndex] = oneOffMemberId;
|
newOneOffMembers[existingIndex] = oneOffMemberId;
|
||||||
|
|
||||||
// Write back
|
// Write back
|
||||||
props.SetProperties(
|
SetProperties(
|
||||||
new string[] { OutlookConstants.PR_DISTLIST_MEMBERS, OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS },
|
new string[] { OutlookConstants.PR_DISTLIST_MEMBERS, OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS },
|
||||||
new object[] { newMembers, newOneOffMembers }
|
new object[] { newMembers, newOneOffMembers }
|
||||||
);
|
);
|
||||||
@ -178,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,14 +195,27 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public override string ToString() { return "DistributionList: " + DLName; }
|
#region Wrapper methods
|
||||||
|
|
||||||
public string DLName
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
{
|
{
|
||||||
get { return _item.DLName; }
|
return _item.UserProperties;
|
||||||
set { _item.DLName = value; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
|
{
|
||||||
|
return _item.PropertyAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "DistributionList: " + DLName;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
get { return _item.Body; }
|
get { return _item.Body; }
|
||||||
@ -233,40 +228,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Subject = value; }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFolder Parent { get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } }
|
public void Save() { _item.Save(); }
|
||||||
public string ParentEntryId
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
|
public IFolder Parent
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
return parent?.EntryID;
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStore GetStore()
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
public string StoreID
|
||||||
public string StoreId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// TODO: release needed
|
using (ComRelease com = new ComRelease())
|
||||||
return _item.Parent?.Store?.StoreID;
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string StoreDisplayName
|
public string StoreDisplayName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
// TODO: release needed
|
using (ComRelease com = new ComRelease())
|
||||||
return _item.Parent?.Store?.DisplayName;
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
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.OutlookWrappers
|
||||||
|
{
|
||||||
|
class ExplorerWrapper : ComWrapper<NSOutlook.Explorer>, IExplorer
|
||||||
|
{
|
||||||
|
public ExplorerWrapper(NSOutlook.Explorer item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ExplorerEvents_10_SelectionChangeEventHandler SelectionChange
|
||||||
|
{
|
||||||
|
add { _item.SelectionChange += value; }
|
||||||
|
remove { _item.SelectionChange -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
base.DoRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommandBars GetCommandBars()
|
||||||
|
{
|
||||||
|
return new CommandBarsWrapper(_item.CommandBars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFolder GetCurrentFolder()
|
||||||
|
{
|
||||||
|
return _item.CurrentFolder.Wrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -23,38 +22,65 @@ using System.Threading.Tasks;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
public class FolderWrapper : OutlookWrapper<Folder>, IFolder
|
class FolderWrapper : OutlookWrapper<NSOutlook.Folder>, IFolder
|
||||||
{
|
{
|
||||||
public FolderWrapper(Folder folder)
|
public FolderWrapper(NSOutlook.MAPIFolder folder)
|
||||||
:
|
:
|
||||||
base(folder)
|
base((NSOutlook.Folder)folder)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
base.DoRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NSOutlook.MAPIFolder CloneComObject()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Application app = com.Add(_item.Application);
|
||||||
|
NSOutlook.NameSpace session = com.Add(app.Session);
|
||||||
|
NSOutlook.MAPIFolder folder = session.GetFolderFromID(EntryID);
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual public IFolder Clone()
|
||||||
|
{
|
||||||
|
return new FolderWrapper(CloneComObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal NSOutlook.Folder RawItem { get { return _item; } }
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
{
|
{
|
||||||
return _item.PropertyAccessor;
|
return _item.PropertyAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FullFolderPath { get { return _item.FullFolderPath; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,17 +95,20 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
using (ComRelease com = new ComRelease())
|
using (ComRelease com = new ComRelease())
|
||||||
{
|
{
|
||||||
// The parent of the root item is a session, not null. Hence the explicit type checks.
|
// The parent of the root item is a session, not null. Hence the explicit type checks.
|
||||||
Folder current = _item;
|
// _item is managed by this wrapper and does not need to be released.
|
||||||
|
NSOutlook.Folder current = _item;
|
||||||
for (int i = 0; i < depth; ++i)
|
for (int i = 0; i < depth; ++i)
|
||||||
{
|
{
|
||||||
object parent = current.Parent;
|
object parent = com.Add(current.Parent);
|
||||||
com.Add(parent);
|
|
||||||
if (!(parent is Folder))
|
current = parent as NSOutlook.Folder;
|
||||||
|
if (current == null)
|
||||||
return false;
|
return false;
|
||||||
current = (Folder)parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return !(com.Add(current.Parent) is Folder);
|
// Check if the remaining parent is a folder
|
||||||
|
object finalParent = com.Add(current.Parent);
|
||||||
|
return !(finalParent is NSOutlook.Folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +121,15 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Store); } }
|
public IStore GetStore() { return Mapping.Wrap(_item.Store); }
|
||||||
public string StoreId
|
|
||||||
|
public string StoreID
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
using (IStore store = Store)
|
using (IStore store = GetStore())
|
||||||
{
|
{
|
||||||
return store.StoreID;
|
return store.StoreID;
|
||||||
}
|
}
|
||||||
@ -109,7 +139,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
using (IStore store = Store)
|
using (IStore store = GetStore())
|
||||||
{
|
{
|
||||||
return store.DisplayName;
|
return store.DisplayName;
|
||||||
}
|
}
|
||||||
@ -118,119 +148,20 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
|
|
||||||
public ItemType ItemType { get { return (ItemType)(int)_item.DefaultItemType; } }
|
public ItemType ItemType { get { return (ItemType)(int)_item.DefaultItemType; } }
|
||||||
|
|
||||||
public class IItemsEnumerator<ItemType> : IEnumerator<ItemType>
|
|
||||||
where ItemType : IItem
|
|
||||||
{
|
|
||||||
private Items _items;
|
|
||||||
private IEnumerator _enum;
|
|
||||||
private ItemType _last;
|
|
||||||
|
|
||||||
public IItemsEnumerator(Folder _folder, string field, bool descending)
|
public IItems Items
|
||||||
{
|
|
||||||
this._items = _folder.Items;
|
|
||||||
if (field != null)
|
|
||||||
{
|
|
||||||
this._items.Sort("[" + field + "]", descending);
|
|
||||||
}
|
|
||||||
this._enum = _items.GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemType Current
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_last != null)
|
return new ItemsWrapper(this);
|
||||||
{
|
|
||||||
_last.Dispose();
|
|
||||||
_last = default(ItemType);
|
|
||||||
}
|
}
|
||||||
_last = Mapping.Wrap<ItemType>(_enum.Current);
|
|
||||||
return _last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object IEnumerator.Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_enum != null)
|
|
||||||
{
|
|
||||||
if (_enum is IDisposable)
|
|
||||||
((IDisposable)_enum).Dispose();
|
|
||||||
_enum = null;
|
|
||||||
}
|
|
||||||
if (_items != null)
|
|
||||||
{
|
|
||||||
ComRelease.Release(_items);
|
|
||||||
_items = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (_last != null)
|
|
||||||
{
|
|
||||||
_last.Dispose();
|
|
||||||
_last = default(ItemType);
|
|
||||||
}
|
|
||||||
return _enum.MoveNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_enum.Reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IItemsEnumerable<ItemType> : IEnumerable<ItemType>
|
|
||||||
where ItemType : IItem
|
|
||||||
{
|
|
||||||
private readonly Folder _folder;
|
|
||||||
private readonly string _field;
|
|
||||||
private readonly bool _descending;
|
|
||||||
|
|
||||||
public IItemsEnumerable(Folder folder, string field, bool descending)
|
|
||||||
{
|
|
||||||
this._folder = folder;
|
|
||||||
this._field = field;
|
|
||||||
this._descending = descending;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<ItemType> GetEnumerator()
|
|
||||||
{
|
|
||||||
return new IItemsEnumerator<ItemType>(_folder, _field, _descending);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IItem> Items
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new IItemsEnumerable<IItem>(_item, null, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<IItem> ItemsSorted(string field, bool descending)
|
|
||||||
{
|
|
||||||
return new IItemsEnumerable<IItem>(_item, field, descending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IItem GetItemById(string entryId)
|
public IItem GetItemById(string entryId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (IStore store = Store)
|
using (IStore store = GetStore())
|
||||||
{
|
{
|
||||||
return store.GetItemFromID(entryId);
|
return store.GetItemFromID(entryId);
|
||||||
}
|
}
|
||||||
@ -270,77 +201,76 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
return new SearchWrapper<ItemType>(_item.Items);
|
return new SearchWrapper<ItemType>(_item.Items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Subfolders
|
||||||
|
|
||||||
public IEnumerable<FolderType> GetSubFolders<FolderType>()
|
public IEnumerable<FolderType> GetSubFolders<FolderType>()
|
||||||
where FolderType : IFolder
|
where FolderType : IFolder
|
||||||
{
|
{
|
||||||
foreach (MAPIFolder folder in _item.Folders)
|
// Don't release the items, the wrapper manages them
|
||||||
|
foreach (NSOutlook.Folder folder in _item.Folders.ComEnum(false))
|
||||||
{
|
{
|
||||||
yield return WrapFolder<FolderType>(folder);
|
yield return folder.Wrap<FolderType>();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IFolders SubFolders
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return new FoldersWrapper(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public FolderType GetSubFolder<FolderType>(string name)
|
public FolderType GetSubFolder<FolderType>(string name)
|
||||||
where FolderType : IFolder
|
where FolderType : IFolder
|
||||||
{
|
{
|
||||||
// Fetching the folder by name throws an exception if not found, loop and find
|
// Fetching the folder by name throws an exception if not found, loop and find
|
||||||
// to prevent exceptions in the log
|
// to prevent exceptions in the log.
|
||||||
MAPIFolder sub = null;
|
// Don't release the items in RawEnum, they are release manually or handed to WrapFolders.
|
||||||
foreach(MAPIFolder folder in _item.Folders)
|
NSOutlook.Folder sub = null;
|
||||||
|
foreach(NSOutlook.Folder folder in _item.Folders.ComEnum(false))
|
||||||
{
|
{
|
||||||
if (folder.Name == name)
|
if (folder.Name == name)
|
||||||
{
|
{
|
||||||
sub = folder;
|
sub = folder;
|
||||||
break;
|
break; // TODO: does this prevent the rest of the objects from getting released?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ComRelease.Release(folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sub == null)
|
if (sub == null)
|
||||||
return default(FolderType);
|
return default(FolderType);
|
||||||
return WrapFolder<FolderType>(sub);
|
return sub.Wrap<FolderType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FolderType CreateFolder<FolderType>(string name)
|
public FolderType CreateFolder<FolderType>(string name)
|
||||||
where FolderType : IFolder
|
where FolderType : IFolder
|
||||||
{
|
{
|
||||||
Folders folders = _item.Folders;
|
using (ComRelease com = new ComRelease())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
NSOutlook.Folders folders = com.Add(_item.Folders);
|
||||||
if (typeof(FolderType) == typeof(IFolder))
|
if (typeof(FolderType) == typeof(IFolder))
|
||||||
{
|
{
|
||||||
return WrapFolder<FolderType>(folders.Add(name));
|
return folders.Add(name).Wrap<FolderType>();
|
||||||
}
|
}
|
||||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||||
{
|
{
|
||||||
MAPIFolder newFolder = folders.Add(name, OlDefaultFolders.olFolderContacts);
|
NSOutlook.MAPIFolder newFolder = folders.Add(name, NSOutlook.OlDefaultFolders.olFolderContacts);
|
||||||
newFolder.ShowAsOutlookAB = true;
|
newFolder.ShowAsOutlookAB = true;
|
||||||
return WrapFolder<FolderType>(newFolder);
|
return newFolder.Wrap<FolderType>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(folders);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FolderType WrapFolder<FolderType>(MAPIFolder folder)
|
#endregion
|
||||||
where FolderType : IFolder
|
|
||||||
{
|
|
||||||
if (typeof(FolderType) == typeof(IFolder))
|
|
||||||
{
|
|
||||||
return (FolderType)(IFolder)new FolderWrapper((Folder)folder);
|
|
||||||
}
|
|
||||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
|
||||||
{
|
|
||||||
return (FolderType)(IFolder)new AddressBookWrapper((Folder)folder);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStorageItem GetStorageItem(string name)
|
public IStorageItem GetStorageItem(string name)
|
||||||
{
|
{
|
||||||
StorageItem item = _item.GetStorage(name, OlStorageIdentifierType.olIdentifyBySubject);
|
NSOutlook.StorageItem item = _item.GetStorage(name, NSOutlook.OlStorageIdentifierType.olIdentifyBySubject);
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return null;
|
return null;
|
||||||
return new StorageItemWrapper(item);
|
return new StorageItemWrapper(item);
|
||||||
@ -355,16 +285,12 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
public ItemType Create<ItemType>()
|
public ItemType Create<ItemType>()
|
||||||
where ItemType : IItem
|
where ItemType : IItem
|
||||||
{
|
{
|
||||||
Items items = _item.Items;
|
using (ComRelease com = new ComRelease())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
NSOutlook.Items items = com.Add(_item.Items);
|
||||||
object item = items.Add(Mapping.OutlookItemType<ItemType>());
|
object item = items.Add(Mapping.OutlookItemType<ItemType>());
|
||||||
return Mapping.Wrap<ItemType>(item);
|
return Mapping.Wrap<ItemType>(item);
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(items);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -411,14 +337,14 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
_item.BeforeItemMove -= HandleBeforeItemMove;
|
_item.BeforeItemMove -= HandleBeforeItemMove;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleBeforeItemMove(object item, MAPIFolder target, ref bool cancel)
|
private void HandleBeforeItemMove(object item, NSOutlook.MAPIFolder target, ref bool cancel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_beforeItemMove != null)
|
if (_beforeItemMove != null)
|
||||||
{
|
{
|
||||||
using (IItem itemWrapped = Mapping.Wrap<IItem>(item))
|
using (IItem itemWrapped = Mapping.Wrap<IItem>(item, false))
|
||||||
using (IFolder targetWrapped = Mapping.Wrap<IFolder>(target))
|
using (IFolder targetWrapped = Mapping.Wrap<IFolder>(target, false))
|
||||||
{
|
{
|
||||||
if (itemWrapped != null && targetWrapped != null)
|
if (itemWrapped != null && targetWrapped != null)
|
||||||
{
|
{
|
||||||
@ -435,5 +361,15 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
public ItemType DefaultItemType
|
||||||
|
{
|
||||||
|
get { return (ItemType)(int)_item.DefaultItemType; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZPushFolder ZPush
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,215 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class FoldersWrapper : IFolders
|
||||||
|
{
|
||||||
|
// Managed by the caller, not released here
|
||||||
|
private readonly FolderWrapper _folder;
|
||||||
|
|
||||||
|
public FoldersWrapper(FolderWrapper folder)
|
||||||
|
{
|
||||||
|
this._folder = folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IFolder> GetEnumerator()
|
||||||
|
{
|
||||||
|
// Don't release the items, the wrapper manages them
|
||||||
|
foreach (NSOutlook.Folder folder in _folder.RawItem.Folders.ComEnum(false))
|
||||||
|
{
|
||||||
|
yield return folder.Wrap<IFolder>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
// Don't release the items, the wrapper manages them
|
||||||
|
foreach (NSOutlook.Folder folder in _folder.RawItem.Folders.ComEnum(false))
|
||||||
|
{
|
||||||
|
yield return folder.Wrap<IFolder>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
private class EventsWrapper : ComWrapper<NSOutlook.Folders>, IFolders_Events
|
||||||
|
{
|
||||||
|
public EventsWrapper(NSOutlook.Folders item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region FolderAdd
|
||||||
|
|
||||||
|
private IFolders_FolderEventHandler _folderAdd;
|
||||||
|
public event IFolders_FolderEventHandler FolderAdd
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
if (_folderAdd == null)
|
||||||
|
HookFolderAdd(true);
|
||||||
|
_folderAdd += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_folderAdd -= value;
|
||||||
|
if (_folderAdd == null)
|
||||||
|
HookFolderAdd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HookFolderAdd(bool hook)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
_item.FolderAdd += HandleFolderAdd;
|
||||||
|
else
|
||||||
|
_item.FolderAdd -= HandleFolderAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFolderAdd(NSOutlook.MAPIFolder folder)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_folderAdd != null)
|
||||||
|
{
|
||||||
|
using (IFolder folderWrapped = Mapping.Wrap<IFolder>(folder, false))
|
||||||
|
{
|
||||||
|
if (folderWrapped != null)
|
||||||
|
{
|
||||||
|
_folderAdd(folderWrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in HandleFolderAdd: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region FolderChange
|
||||||
|
|
||||||
|
private IFolders_FolderEventHandler _folderChange;
|
||||||
|
public event IFolders_FolderEventHandler FolderChange
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
if (_folderChange == null)
|
||||||
|
HookFolderChange(true);
|
||||||
|
_folderChange += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_folderChange -= value;
|
||||||
|
if (_folderChange == null)
|
||||||
|
HookFolderChange(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HookFolderChange(bool hook)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
_item.FolderChange += HandleFolderChange;
|
||||||
|
else
|
||||||
|
_item.FolderChange -= HandleFolderChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFolderChange(NSOutlook.MAPIFolder folder)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_folderChange != null)
|
||||||
|
{
|
||||||
|
using (IFolder folderWrapped = Mapping.Wrap<IFolder>(folder, false))
|
||||||
|
{
|
||||||
|
if (folderWrapped != null)
|
||||||
|
{
|
||||||
|
_folderChange(folderWrapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in HandleFolderChange: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region FolderRemove
|
||||||
|
|
||||||
|
private IFolders_EventHandler _folderRemove;
|
||||||
|
public event IFolders_EventHandler FolderRemove
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
if (_folderRemove == null)
|
||||||
|
HookFolderRemove(true);
|
||||||
|
_folderRemove += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_folderRemove -= value;
|
||||||
|
if (_folderRemove == null)
|
||||||
|
HookFolderRemove(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HookFolderRemove(bool hook)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
_item.FolderRemove += HandleFolderRemove;
|
||||||
|
else
|
||||||
|
_item.FolderRemove -= HandleFolderRemove;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFolderRemove()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_folderRemove != null)
|
||||||
|
{
|
||||||
|
_folderRemove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in HandleFolderRemove: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFolders_Events GetEvents()
|
||||||
|
{
|
||||||
|
return new EventsWrapper(_folder.RawItem.Folders);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,193 @@
|
|||||||
|
/// Copyright 2017 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;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class ItemEventsWrapper : ComWrapper<NSOutlook.ItemEvents_10_Event>, IItemEvents
|
||||||
|
{
|
||||||
|
internal ItemEventsWrapper(NSOutlook.ItemEvents_10_Event item) : base(item)
|
||||||
|
{
|
||||||
|
MustRelease = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_AfterWriteEventHandler AfterWrite
|
||||||
|
{
|
||||||
|
add { _item.AfterWrite += value; }
|
||||||
|
remove { _item.AfterWrite -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_AttachmentAddEventHandler AttachmentAdd
|
||||||
|
{
|
||||||
|
add { _item.AttachmentAdd += value; }
|
||||||
|
remove { _item.AttachmentAdd -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_AttachmentReadEventHandler AttachmentRead
|
||||||
|
{
|
||||||
|
add { _item.AttachmentRead += value; }
|
||||||
|
remove { _item.AttachmentRead -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_AttachmentRemoveEventHandler AttachmentRemove
|
||||||
|
{
|
||||||
|
add { _item.AttachmentRemove += value; }
|
||||||
|
remove { _item.AttachmentRemove -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAttachmentAddEventHandler BeforeAttachmentAdd
|
||||||
|
{
|
||||||
|
add { _item.BeforeAttachmentAdd += value; }
|
||||||
|
remove { _item.BeforeAttachmentAdd -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAttachmentPreviewEventHandler BeforeAttachmentPreview
|
||||||
|
{
|
||||||
|
add { _item.BeforeAttachmentPreview += value; }
|
||||||
|
remove { _item.BeforeAttachmentPreview -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAttachmentReadEventHandler BeforeAttachmentRead
|
||||||
|
{
|
||||||
|
add { _item.BeforeAttachmentRead += value; }
|
||||||
|
remove { _item.BeforeAttachmentRead -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAttachmentSaveEventHandler BeforeAttachmentSave
|
||||||
|
{
|
||||||
|
add { _item.BeforeAttachmentSave += value; }
|
||||||
|
remove { _item.BeforeAttachmentSave -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAttachmentWriteToTempFileEventHandler BeforeAttachmentWriteToTempFile
|
||||||
|
{
|
||||||
|
add { _item.BeforeAttachmentWriteToTempFile += value; }
|
||||||
|
remove { _item.BeforeAttachmentWriteToTempFile -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeAutoSaveEventHandler BeforeAutoSave
|
||||||
|
{
|
||||||
|
add { _item.BeforeAutoSave += value; }
|
||||||
|
remove { _item.BeforeAutoSave -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeCheckNamesEventHandler BeforeCheckNames
|
||||||
|
{
|
||||||
|
add { _item.BeforeCheckNames += value; }
|
||||||
|
remove { _item.BeforeCheckNames -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeDeleteEventHandler BeforeDelete
|
||||||
|
{
|
||||||
|
add { _item.BeforeDelete += value; }
|
||||||
|
remove { _item.BeforeDelete -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_BeforeReadEventHandler BeforeRead
|
||||||
|
{
|
||||||
|
add { _item.BeforeRead += value; }
|
||||||
|
remove { _item.BeforeRead -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_CloseEventHandler Close
|
||||||
|
{
|
||||||
|
add { _item.Close += value; }
|
||||||
|
remove { _item.Close -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_CustomActionEventHandler CustomAction
|
||||||
|
{
|
||||||
|
add { _item.CustomAction += value; }
|
||||||
|
remove { _item.CustomAction -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_CustomPropertyChangeEventHandler CustomPropertyChange
|
||||||
|
{
|
||||||
|
add { _item.CustomPropertyChange += value; }
|
||||||
|
remove { _item.CustomPropertyChange -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_ForwardEventHandler Forward
|
||||||
|
{
|
||||||
|
add { _item.Forward += value; }
|
||||||
|
remove { _item.Forward -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_OpenEventHandler Open
|
||||||
|
{
|
||||||
|
add { _item.Open += value; }
|
||||||
|
remove { _item.Open -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_PropertyChangeEventHandler PropertyChange
|
||||||
|
{
|
||||||
|
add { _item.PropertyChange += value; }
|
||||||
|
remove { _item.PropertyChange -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_ReadEventHandler Read
|
||||||
|
{
|
||||||
|
add { _item.Read += value; }
|
||||||
|
remove { _item.Read -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_ReadCompleteEventHandler ReadComplete
|
||||||
|
{
|
||||||
|
add { _item.ReadComplete += value; }
|
||||||
|
remove { _item.ReadComplete -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_ReplyEventHandler Reply
|
||||||
|
{
|
||||||
|
add { _item.Reply += value; }
|
||||||
|
remove { _item.Reply -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_ReplyAllEventHandler ReplyAll
|
||||||
|
{
|
||||||
|
add { _item.ReplyAll += value; }
|
||||||
|
remove { _item.ReplyAll -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_SendEventHandler Send
|
||||||
|
{
|
||||||
|
add { _item.Send += value; }
|
||||||
|
remove { _item.Send -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_UnloadEventHandler Unload
|
||||||
|
{
|
||||||
|
add { _item.Unload += value; }
|
||||||
|
remove { _item.Unload -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.ItemEvents_10_WriteEventHandler Write
|
||||||
|
{
|
||||||
|
add { _item.Write += value; }
|
||||||
|
remove { _item.Write -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,269 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class ItemsWrapper : IItems
|
||||||
|
{
|
||||||
|
// Managed by the caller, not released here
|
||||||
|
private readonly FolderWrapper _folder;
|
||||||
|
|
||||||
|
private string _field;
|
||||||
|
private bool _descending;
|
||||||
|
|
||||||
|
public ItemsWrapper(FolderWrapper folder)
|
||||||
|
{
|
||||||
|
this._folder = folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IItems Sort(string field, bool descending)
|
||||||
|
{
|
||||||
|
this._field = field;
|
||||||
|
this._descending = descending;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<T> Typed<T>() where T: IItem
|
||||||
|
{
|
||||||
|
foreach(IItem item in this)
|
||||||
|
{
|
||||||
|
if (typeof(T).IsInstanceOfType(item))
|
||||||
|
{
|
||||||
|
yield return (T)item;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private NSOutlook.Items GetItems()
|
||||||
|
{
|
||||||
|
return _folder.RawItem.Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IItem> GetEnumerator()
|
||||||
|
{
|
||||||
|
return new ItemsEnumerator<IItem>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Enumeration
|
||||||
|
|
||||||
|
public class ItemsEnumerator<ItemType> : ComWrapper<NSOutlook.Items>, IEnumerator<ItemType>
|
||||||
|
where ItemType : IItem
|
||||||
|
{
|
||||||
|
private IEnumerator _enum;
|
||||||
|
private ItemType _last;
|
||||||
|
|
||||||
|
public ItemsEnumerator(ItemsWrapper items) : base(items.GetItems())
|
||||||
|
{
|
||||||
|
// Apply any sort options
|
||||||
|
if (items._field != null)
|
||||||
|
{
|
||||||
|
this._item.Sort("[" + items._field + "]", items._descending);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the enumerator
|
||||||
|
this._enum = _item.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
CleanLast();
|
||||||
|
if (_enum != null)
|
||||||
|
{
|
||||||
|
if (_enum is IDisposable)
|
||||||
|
((IDisposable)_enum).Dispose();
|
||||||
|
ComRelease.Release(_enum);
|
||||||
|
_enum = null;
|
||||||
|
}
|
||||||
|
base.DoRelease();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemType Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
CleanLast();
|
||||||
|
_last = Mapping.Wrap<ItemType>(_enum.Current);
|
||||||
|
return _last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object IEnumerator.Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CleanLast()
|
||||||
|
{
|
||||||
|
if (_last != null)
|
||||||
|
{
|
||||||
|
_last.Dispose();
|
||||||
|
_last = default(ItemType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
CleanLast();
|
||||||
|
return _enum.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
CleanLast();
|
||||||
|
_enum.Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
private class EventsWrapper : ComWrapper<NSOutlook.Items>, IItems_Events
|
||||||
|
{
|
||||||
|
public EventsWrapper(NSOutlook.Items item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region ItemAdd
|
||||||
|
|
||||||
|
private IItems_ItemEventHandler _itemAdd;
|
||||||
|
public event IItems_ItemEventHandler ItemAdd
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
if (_itemAdd == null)
|
||||||
|
HookItemAdd(true);
|
||||||
|
_itemAdd += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_itemAdd -= value;
|
||||||
|
if (_itemAdd == null)
|
||||||
|
HookItemAdd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HookItemAdd(bool hook)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
_item.ItemAdd += HandleItemAdd;
|
||||||
|
else
|
||||||
|
_item.ItemAdd -= HandleItemAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleItemAdd(object objItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_itemAdd != null)
|
||||||
|
{
|
||||||
|
using (IItem item = Mapping.Wrap<IItem>(objItem, false))
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
_itemAdd(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in HandleItemAdd: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ItemChange
|
||||||
|
|
||||||
|
private IItems_ItemEventHandler _itemChange;
|
||||||
|
public event IItems_ItemEventHandler ItemChange
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
if (_itemChange == null)
|
||||||
|
HookItemChange(true);
|
||||||
|
_itemChange += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
_itemChange -= value;
|
||||||
|
if (_itemChange == null)
|
||||||
|
HookItemChange(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HookItemChange(bool hook)
|
||||||
|
{
|
||||||
|
if (hook)
|
||||||
|
_item.ItemChange += HandleItemChange;
|
||||||
|
else
|
||||||
|
_item.ItemChange -= HandleItemChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleItemChange(object objItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_itemChange != null)
|
||||||
|
{
|
||||||
|
using (IItem item = Mapping.Wrap<IItem>(objItem, false))
|
||||||
|
{
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
_itemChange(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in HandleItemChange: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
public IItems_Events GetEvents()
|
||||||
|
{
|
||||||
|
return new EventsWrapper(GetItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -19,27 +19,95 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class MailItemWrapper : OutlookWrapper<MailItem>, IMailItem
|
class MailItemWrapper : OutlookItemWrapper<NSOutlook.MailItem>, IMailItem
|
||||||
{
|
{
|
||||||
internal MailItemWrapper(MailItem item)
|
internal MailItemWrapper(NSOutlook.MailItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region IMailItem implementation
|
||||||
|
|
||||||
|
public DateTime? AttrLastVerbExecutionTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME) as DateTime?;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AttrLastVerbExecuted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (int)GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SenderEmailAddress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
return com.Add(_item.Sender)?.Address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SenderName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
return com.Add(_item.Sender)?.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SetSender(IAddressEntry addressEntry)
|
||||||
|
{
|
||||||
|
_item.Sender = ((AddressEntryWrapper)addressEntry).RawItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
return _item.UserProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
{
|
{
|
||||||
return _item.PropertyAccessor;
|
return _item.PropertyAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() { return "Mail: " + Subject; }
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Mail:" + Subject;
|
||||||
|
}
|
||||||
|
|
||||||
#region Properties
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
@ -53,37 +121,53 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Subject = value; }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStore Store
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
|
public IFolder Parent
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = (Folder)_item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return StoreWrapper.Wrap(parent?.Store);
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string StoreId
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = (Folder)_item.Parent;
|
using (ComRelease com = new ComRelease())
|
||||||
Store store = null;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
store = parent?.Store;
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
return store?.StoreID;
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
}
|
return store.StoreID;
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(parent);
|
|
||||||
ComRelease.Release(store);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,76 +176,17 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = (Folder)_item.Parent;
|
using (ComRelease com = new ComRelease())
|
||||||
Store store = null;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
store = parent?.Store;
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
return store?.DisplayName;
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
}
|
return store.StoreID;
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(parent);
|
|
||||||
ComRelease.Release(store);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SenderEmailAddress
|
public void Delete() { _item.Delete(); }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
// TODO: should Sender be released?
|
|
||||||
return _item.Sender?.Address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SenderName
|
|
||||||
{
|
|
||||||
get { return _item.Sender?.Name; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void SetSender(AddressEntry addressEntry)
|
|
||||||
{
|
|
||||||
_item.Sender = addressEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public IFolder Parent
|
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
Folder parent = _item.Parent;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,15 +15,16 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
|
// TODO: a clean up is needed, move as much as possible to Wrappers.cs
|
||||||
public static class Mapping
|
public static class Mapping
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -32,40 +33,42 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="o">The Outlook object.</param>
|
/// <param name="o">The Outlook object.</param>
|
||||||
/// <returns>The IItem wrapper, or null if the object could not be wrapped</returns>
|
/// <returns>The IItem wrapper, or null if the object could not be wrapped</returns>
|
||||||
public static IBase Wrap(object o, bool mustRelease = true)
|
private static IBase Wrap(object o, bool mustRelease = true)
|
||||||
{
|
{
|
||||||
if (o == null)
|
if (o == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
IBase wrapper = CreateWrapper(o);
|
IBase wrapper = CreateWrapper(o, mustRelease);
|
||||||
if (wrapper != null)
|
if (wrapper != null)
|
||||||
wrapper.MustRelease = mustRelease;
|
wrapper.MustRelease = mustRelease;
|
||||||
ComRelease.LogWrapper(o, wrapper);
|
ComRelease.LogWrapper(o, wrapper);
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IBase CreateWrapper(object o)
|
private static IBase CreateWrapper(object o, bool mustRelease)
|
||||||
{
|
{
|
||||||
// TODO: switch on o.Class
|
// TODO: switch on o.Class
|
||||||
if (o is MailItem)
|
if (o is NSOutlook.MailItem)
|
||||||
return new MailItemWrapper((MailItem)o);
|
return new MailItemWrapper((NSOutlook.MailItem)o);
|
||||||
if (o is AppointmentItem)
|
if (o is NSOutlook.AppointmentItem)
|
||||||
return new AppointmentItemWrapper((AppointmentItem)o);
|
return new AppointmentItemWrapper((NSOutlook.AppointmentItem)o);
|
||||||
if (o is Folder)
|
if (o is NSOutlook.Folder)
|
||||||
return new FolderWrapper((Folder)o);
|
return new FolderWrapper((NSOutlook.Folder)o);
|
||||||
if (o is ContactItem)
|
if (o is NSOutlook.ContactItem)
|
||||||
return new ContactItemWrapper((ContactItem)o);
|
return new ContactItemWrapper((NSOutlook.ContactItem)o);
|
||||||
if (o is DistListItem)
|
if (o is NSOutlook.DistListItem)
|
||||||
return new DistributionListWrapper((DistListItem)o);
|
return new DistributionListWrapper((NSOutlook.DistListItem)o);
|
||||||
if (o is NoteItem)
|
if (o is NSOutlook.NoteItem)
|
||||||
return new NoteItemWrapper((NoteItem)o);
|
return new NoteItemWrapper((NSOutlook.NoteItem)o);
|
||||||
if (o is TaskItem)
|
if (o is NSOutlook.TaskItem)
|
||||||
return new TaskItemWrapper((TaskItem)o);
|
return new TaskItemWrapper((NSOutlook.TaskItem)o);
|
||||||
|
|
||||||
// TODO: support this?
|
|
||||||
if (o is ReportItem)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
|
// TODO: support others?
|
||||||
|
if (mustRelease)
|
||||||
|
{
|
||||||
|
// The caller assumes a wrapper will be returned, so any lingering object here will never be released.
|
||||||
|
ComRelease.Release(o);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,59 +78,64 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
return (Type)Wrap(o, mustRelease);
|
return (Type)Wrap(o, mustRelease);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IRecipient Wrap(NSOutlook.Recipient r, bool mustRelease = true)
|
||||||
|
{
|
||||||
|
if (r == null)
|
||||||
|
return null;
|
||||||
|
RecipientWrapper wrapped = new RecipientWrapper(r);
|
||||||
|
wrapped.MustRelease = mustRelease;
|
||||||
|
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?
|
||||||
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
|
||||||
{
|
{
|
||||||
IBase wrapped = Wrap(o, mustRelease);
|
IBase wrapped = Wrap(o, mustRelease);
|
||||||
if (wrapped is Type)
|
if (wrapped is Type)
|
||||||
return (Type)wrapped;
|
return (Type)wrapped;
|
||||||
|
|
||||||
|
// Release if required
|
||||||
if (wrapped != null)
|
if (wrapped != null)
|
||||||
wrapped.Dispose();
|
wrapped.Dispose();
|
||||||
return default(Type);
|
return default(Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OlItemType OutlookItemType<ItemType>()
|
public static NSOutlook.OlItemType OutlookItemType<ItemType>()
|
||||||
where ItemType: IItem
|
where ItemType: IItem
|
||||||
{
|
{
|
||||||
Type type = typeof(ItemType);
|
Type type = typeof(ItemType);
|
||||||
if (type == typeof(IContactItem))
|
if (type == typeof(IContactItem))
|
||||||
return OlItemType.olContactItem;
|
return NSOutlook.OlItemType.olContactItem;
|
||||||
if (type == typeof(IDistributionList))
|
if (type == typeof(IDistributionList))
|
||||||
return OlItemType.olDistributionListItem;
|
return NSOutlook.OlItemType.olDistributionListItem;
|
||||||
throw new NotImplementedException(); // TODO
|
throw new NotImplementedException(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OlUserPropertyType OutlookPropertyType<PropType>()
|
public static NSOutlook.OlUserPropertyType OutlookPropertyType<PropType>()
|
||||||
{
|
{
|
||||||
Type type = typeof(PropType);
|
Type type = typeof(PropType);
|
||||||
if (type == typeof(string))
|
if (type == typeof(string))
|
||||||
return OlUserPropertyType.olText;
|
return NSOutlook.OlUserPropertyType.olText;
|
||||||
if (type == typeof(DateTime))
|
if (type == typeof(DateTime))
|
||||||
return OlUserPropertyType.olDateTime;
|
return NSOutlook.OlUserPropertyType.olDateTime;
|
||||||
if (type == typeof(int))
|
if (type == typeof(int))
|
||||||
return OlUserPropertyType.olInteger;
|
return NSOutlook.OlUserPropertyType.olInteger;
|
||||||
if (type.IsEnum)
|
if (type.IsEnum)
|
||||||
return OlUserPropertyType.olInteger;
|
return NSOutlook.OlUserPropertyType.olInteger;
|
||||||
if (type == typeof(string[]))
|
if (type == typeof(string[]))
|
||||||
return OlUserPropertyType.olKeywords;
|
return NSOutlook.OlUserPropertyType.olKeywords;
|
||||||
throw new NotImplementedException(); // TODO
|
throw new NotImplementedException(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: this needs to go elsewhere
|
|
||||||
public static IFolder GetFolderFromID(string folderId)
|
|
||||||
{
|
|
||||||
NameSpace nmspace = ThisAddIn.Instance.Application.Session;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Folder f = (Folder)nmspace.GetFolderFromID(folderId);
|
|
||||||
return Wrap<IFolder>(f);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(nmspace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,32 +14,44 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
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.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
public class NoteItemWrapper : OutlookWrapper<NoteItem>, INoteItem
|
class NoteItemWrapper : OutlookItemWrapper<NSOutlook.NoteItem>, INoteItem
|
||||||
{
|
{
|
||||||
internal NoteItemWrapper(NoteItem item)
|
internal NoteItemWrapper(NSOutlook.NoteItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("NoteItem does not support user properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
{
|
{
|
||||||
return _item.PropertyAccessor;
|
return _item.PropertyAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() { return "Note: " + Subject; }
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Note:" + Subject;
|
||||||
|
}
|
||||||
|
|
||||||
#region Properties
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
@ -50,48 +62,78 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
public string Subject
|
public string Subject
|
||||||
{
|
{
|
||||||
get { return _item.Subject; }
|
get { return _item.Subject; }
|
||||||
set { throw new NotSupportedException(); }
|
set
|
||||||
}
|
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
|
||||||
// TODO: release needed
|
|
||||||
public string StoreId { get { return _item.Parent?.Store?.StoreID; } }
|
|
||||||
public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException("NoteItem does not support setting body");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreDisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
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.OutlookWrappers
|
||||||
|
{
|
||||||
|
abstract class OutlookItemWrapper<ItemType> : OutlookWrapper<ItemType>
|
||||||
|
{
|
||||||
|
public OutlookItemWrapper(ItemType item)
|
||||||
|
:
|
||||||
|
base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IItemEvents GetEvents()
|
||||||
|
{
|
||||||
|
return new ItemEventsWrapper((NSOutlook.ItemEvents_10_Event)_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type GetUserProperty<Type>(string name)
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.UserProperties userProperties = com.Add(GetUserProperties());
|
||||||
|
NSOutlook.UserProperty prop = com.Add(userProperties.Find(name, true));
|
||||||
|
if (prop == null)
|
||||||
|
return default(Type);
|
||||||
|
|
||||||
|
if (typeof(Type).IsEnum)
|
||||||
|
return typeof(Type).GetEnumValues().GetValue(prop.Value);
|
||||||
|
return prop.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUserProperty<Type>(string name, Type value)
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.UserProperties userProperties = com.Add(GetUserProperties());
|
||||||
|
NSOutlook.UserProperty prop = com.Add(userProperties.Find(name, true));
|
||||||
|
if (prop == null)
|
||||||
|
prop = userProperties.Add(name, Mapping.OutlookPropertyType<Type>());
|
||||||
|
|
||||||
|
if (typeof(Type).IsEnum)
|
||||||
|
{
|
||||||
|
int i = Array.FindIndex(typeof(Type).GetEnumNames(), n => n.Equals(value.ToString()));
|
||||||
|
prop.Value = typeof(Type).GetEnumValues().GetValue(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prop.Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the UserProperties associated with the current item.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An unwrapped UserProperties object. The caller is responsible for releasing this.</returns>
|
||||||
|
abstract protected NSOutlook.UserProperties GetUserProperties();
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,6 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Features.DebugSupport;
|
using Acacia.Features.DebugSupport;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -23,56 +22,45 @@ using Acacia.Utils;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper for Outlook wrapper implementations
|
/// Helper for Outlook wrapper implementations
|
||||||
/// </summary>
|
/// </summary>
|
||||||
abstract public class OutlookWrapper<ItemType> : DisposableWrapper
|
abstract class OutlookWrapper<ItemType> : ComWrapper<ItemType>
|
||||||
{
|
{
|
||||||
|
|
||||||
#region Construction / Destruction
|
#region Construction / Destruction
|
||||||
|
|
||||||
protected ItemType _item;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a wrapper.
|
/// Creates a wrapper.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal OutlookWrapper(ItemType item)
|
internal OutlookWrapper(ItemType item) : base(item)
|
||||||
{
|
|
||||||
this._item = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
~OutlookWrapper()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DoRelease()
|
protected override void DoRelease()
|
||||||
{
|
{
|
||||||
|
// Always release props, as we allocated that
|
||||||
if (_props != null)
|
if (_props != null)
|
||||||
{
|
{
|
||||||
ComRelease.Release(_props);
|
ComRelease.Release(_props);
|
||||||
_props = null;
|
_props = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MustRelease)
|
base.DoRelease();
|
||||||
{
|
|
||||||
if (_item != null)
|
|
||||||
{
|
|
||||||
ComRelease.Release(_item);
|
|
||||||
_item = default(ItemType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties implementation
|
#region Properties implementation
|
||||||
|
|
||||||
private PropertyAccessor _props;
|
// Assigned in Props, released in DoRelease
|
||||||
|
private NSOutlook.PropertyAccessor _props;
|
||||||
|
|
||||||
private PropertyAccessor Props
|
private NSOutlook.PropertyAccessor Props
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -88,7 +76,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
/// Returns the wrapped item's property accessor.
|
/// Returns the wrapped item's property accessor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The property accessor. The caller is responsible for disposing this.</returns>
|
/// <returns>The property accessor. The caller is responsible for disposing this.</returns>
|
||||||
abstract protected PropertyAccessor GetPropertyAccessor();
|
abstract protected NSOutlook.PropertyAccessor GetPropertyAccessor();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -111,39 +99,22 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
public bool AttrHidden
|
public bool AttrHidden
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return Props.GetProperty(OutlookConstants.PR_ATTR_HIDDEN);
|
return Props.GetProperty(OutlookConstants.PR_ATTR_HIDDEN);
|
||||||
}
|
}
|
||||||
|
catch(System.Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Props.SetProperty(OutlookConstants.PR_ATTR_HIDDEN, value);
|
Props.SetProperty(OutlookConstants.PR_ATTR_HIDDEN, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime? AttrLastVerbExecutionTime
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME) as DateTime?;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTION_TIME, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int AttrLastVerbExecuted
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Props.GetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED);
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Props.SetProperty(OutlookConstants.PR_LAST_VERB_EXECUTED, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetProperty(string property)
|
public object GetProperty(string property)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -153,7 +124,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
return null;
|
return null;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
catch(System.Exception) { return null; } // TODO: is this fine everywhere?
|
catch(System.Exception) { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetProperty(string property, object value)
|
public void SetProperty(string property, object value)
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
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.OutlookWrappers
|
||||||
|
{
|
||||||
|
class RecipientWrapper : ComWrapper<NSOutlook.Recipient>, IRecipient
|
||||||
|
{
|
||||||
|
internal RecipientWrapper(NSOutlook.Recipient item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal NSOutlook.Recipient RawItem { get { return _item; } }
|
||||||
|
|
||||||
|
public bool IsResolved
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _item.Resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _item.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Address
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _item.Address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAddressEntry GetAddressEntry()
|
||||||
|
{
|
||||||
|
return new AddressEntryWrapper(_item.AddressEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,12 +19,12 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
class SearchWrapper<ItemType> : ISearch<ItemType>
|
class SearchWrapper<ItemType> : ComWrapper<NSOutlook.Items>, ISearch<ItemType>
|
||||||
where ItemType : IItem
|
where ItemType : IItem
|
||||||
{
|
{
|
||||||
private interface SearchTerm
|
private interface SearchTerm
|
||||||
@ -151,11 +151,13 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<SearchTerm> terms = new List<SearchTerm>();
|
private readonly List<SearchTerm> terms = new List<SearchTerm>();
|
||||||
private readonly Items _items;
|
|
||||||
|
|
||||||
public SearchWrapper(Items items)
|
/// <summary>
|
||||||
|
/// Constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">The items to search. The new object takes ownership</param>
|
||||||
|
public SearchWrapper(NSOutlook.Items items) : base(items)
|
||||||
{
|
{
|
||||||
this._items = items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISearchOperator AddOperator(SearchOperator oper)
|
public ISearchOperator AddOperator(SearchOperator oper)
|
||||||
@ -174,31 +176,42 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
|
|
||||||
public IEnumerable<ItemType> Search(int maxResults)
|
public IEnumerable<ItemType> Search(int maxResults)
|
||||||
{
|
{
|
||||||
List<ItemType> values = new List<ItemType>();
|
|
||||||
string filter = MakeFilter();
|
string filter = MakeFilter();
|
||||||
object value = _items.Find(filter);
|
|
||||||
|
int count = 0;
|
||||||
|
object value = _item.Find(filter);
|
||||||
while(value != null)
|
while(value != null)
|
||||||
{
|
{
|
||||||
if (values.Count < maxResults)
|
if (count < maxResults)
|
||||||
{
|
{
|
||||||
|
// Wrap and add if it returns an object. If not, WrapOrDefault will release it
|
||||||
ItemType wrapped = Mapping.WrapOrDefault<ItemType>(value);
|
ItemType wrapped = Mapping.WrapOrDefault<ItemType>(value);
|
||||||
if (wrapped != null)
|
if (wrapped != null)
|
||||||
{
|
{
|
||||||
values.Add(wrapped);
|
try
|
||||||
|
{
|
||||||
|
yield return wrapped;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
wrapped.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Release if not returned. Keep looping to release any others
|
||||||
ComRelease.Release(value);
|
ComRelease.Release(value);
|
||||||
}
|
}
|
||||||
value = _items.FindNext();
|
value = _item.FindNext();
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
return values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemType SearchOne()
|
public ItemType SearchOne()
|
||||||
{
|
{
|
||||||
object value = _items.Find(MakeFilter());
|
// Wrap manages com object in value
|
||||||
|
object value = _item.Find(MakeFilter());
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return default(ItemType);
|
return default(ItemType);
|
||||||
return Mapping.Wrap<ItemType>(value);
|
return Mapping.Wrap<ItemType>(value);
|
||||||
|
@ -15,31 +15,44 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
public class StorageItemWrapper : OutlookWrapper<StorageItem>, IStorageItem
|
class StorageItemWrapper : OutlookItemWrapper<NSOutlook.StorageItem>, IStorageItem
|
||||||
{
|
{
|
||||||
public StorageItemWrapper(StorageItem item)
|
public StorageItemWrapper(NSOutlook.StorageItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
return _item.UserProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
{
|
{
|
||||||
return _item.PropertyAccessor;
|
return _item.PropertyAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() { return "StorageItem"; }
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "StorageItem";
|
||||||
|
}
|
||||||
|
|
||||||
#region Properties
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
@ -53,45 +66,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
set { _item.Subject = value; }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
|
||||||
// TODO: release needed
|
|
||||||
public string StoreId { get { return _item.Parent?.Store?.StoreID; } }
|
|
||||||
public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreDisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,51 +19,91 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
public class StoreWrapper : DisposableWrapper, IStore
|
class StoreWrapper : ComWrapper<NSOutlook.Store>, IStore
|
||||||
{
|
{
|
||||||
public static IStore Wrap(Store store)
|
internal StoreWrapper(NSOutlook.Store store) : base(store)
|
||||||
{
|
{
|
||||||
return store == null ? null : new StoreWrapper(store);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Store _store;
|
|
||||||
|
|
||||||
private StoreWrapper(Store store)
|
|
||||||
{
|
|
||||||
this._store = store;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DoRelease()
|
|
||||||
{
|
|
||||||
ComRelease.Release(_store);
|
|
||||||
_store = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFolder GetRootFolder()
|
public IFolder GetRootFolder()
|
||||||
{
|
{
|
||||||
return new FolderWrapper((Folder)_store.GetRootFolder());
|
// FolderWrapper manages the returned Folder
|
||||||
|
return new FolderWrapper((NSOutlook.Folder)_item.GetRootFolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
private NSOutlook.MAPIFolder GetDefaultFolderObj(DefaultFolder folder)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (NSOutlook.Folder)_item.GetDefaultFolder((NSOutlook.OlDefaultFolders)(int)folder);
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFolder GetDefaultFolder(DefaultFolder folder)
|
||||||
|
{
|
||||||
|
// FolderWrapper manages the returned Folder
|
||||||
|
return GetDefaultFolderObj(folder).Wrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetDefaultFolderId(DefaultFolder folder)
|
||||||
|
{
|
||||||
|
NSOutlook.MAPIFolder mapiFolder = GetDefaultFolderObj(folder);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return mapiFolder?.EntryID;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(mapiFolder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IItem GetItemFromID(string id)
|
public IItem GetItemFromID(string id)
|
||||||
{
|
{
|
||||||
NameSpace nmspace = _store.Session;
|
using (ComRelease com = new ComRelease())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
|
NSOutlook.NameSpace nmspace = com.Add(_item.Session);
|
||||||
|
|
||||||
|
// Get the item; the wrapper manages it
|
||||||
object o = nmspace.GetItemFromID(id);
|
object o = nmspace.GetItemFromID(id);
|
||||||
return Mapping.Wrap<IItem>(o);
|
return Mapping.Wrap<IItem>(o);
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
ComRelease.Release(nmspace);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DisplayName { get { return _store.DisplayName; } }
|
public string DisplayName { get { return _item.DisplayName; } }
|
||||||
public string StoreID { get { return _store.StoreID; } }
|
public string StoreID { get { return _item.StoreID; } }
|
||||||
|
|
||||||
|
public bool IsFileStore { get { return _item.IsDataFileStore; } }
|
||||||
|
public string FilePath { get { return _item.FilePath; } }
|
||||||
|
|
||||||
|
public void EmptyDeletedItems()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.MAPIFolder f = _item.GetDefaultFolder(NSOutlook.OlDefaultFolders.olFolderDeletedItems);
|
||||||
|
if (f != null)
|
||||||
|
{
|
||||||
|
com.Add(f);
|
||||||
|
|
||||||
|
// Normal enumeration fails when deleting. Do it like this.
|
||||||
|
NSOutlook.Folders folders = com.Add(f.Folders);
|
||||||
|
for (int i = folders.Count; i > 0; --i)
|
||||||
|
com.Add(folders[i]).Delete();
|
||||||
|
|
||||||
|
NSOutlook.Items items = com.Add(f.Items);
|
||||||
|
for (int i = items.Count; i > 0; --i)
|
||||||
|
com.Add(items[i]).Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,306 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Utils;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class StoresWrapper : ComWrapper<NSOutlook.Stores>, IStores
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accounts indexed by store id. Null values are allowed, if a store has been
|
||||||
|
/// determined to not be associated with an Account. This is required to determine when a store is new.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<string, AccountWrapper> _accountsByStoreId = new Dictionary<string, AccountWrapper>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Accounts indexed by SMTPAddress. Null values are not allowed.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<string, AccountWrapper> _accountsBySmtp = new Dictionary<string, AccountWrapper>();
|
||||||
|
|
||||||
|
public StoresWrapper(NSOutlook.Stores item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event IStores_AccountDiscovered AccountDiscovered;
|
||||||
|
public event IStores_AccountRemoved AccountRemoved;
|
||||||
|
|
||||||
|
private void OnAccountDiscovered(AccountWrapper account)
|
||||||
|
{
|
||||||
|
AccountDiscovered?.Invoke(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAccountRemoved(AccountWrapper account)
|
||||||
|
{
|
||||||
|
AccountRemoved?.Invoke(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementation
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
// Check existing stores
|
||||||
|
foreach(NSOutlook.Store store in _item)
|
||||||
|
{
|
||||||
|
Tasks.Task(null, "AddStore", () =>
|
||||||
|
{
|
||||||
|
StoreAdded(store);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register for new stores
|
||||||
|
// The store remove event is not sent, so don't bother registering for that
|
||||||
|
_item.StoreAdd += StoreAdded;
|
||||||
|
|
||||||
|
if (GlobalOptions.INSTANCE.AccountTimer)
|
||||||
|
{
|
||||||
|
// Set up timer to check for removed accounts
|
||||||
|
Util.Timed(null, Config.ACCOUNT_CHECK_INTERVAL, CheckAccountsRemoved);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event handler for Stores.StoreAdded event.
|
||||||
|
/// </summary>
|
||||||
|
private void Event_StoreAdded(NSOutlook.Store _)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Accessing the store object causes random crashes, simply iterate to find new stores
|
||||||
|
Logger.Instance.Trace(this, "StoreAdded");
|
||||||
|
foreach (NSOutlook.Store rawStore in _item)
|
||||||
|
{
|
||||||
|
if (!_accountsByStoreId.ContainsKey(rawStore.StoreID))
|
||||||
|
{
|
||||||
|
StoreAdded(rawStore);
|
||||||
|
}
|
||||||
|
else ComRelease.Release(rawStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Event_StoreAdded Exception: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs the actions required to handle a new store.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rawStore">The new store. Ownership is transferred</param>
|
||||||
|
private void StoreAdded(NSOutlook.Store rawStore)
|
||||||
|
{
|
||||||
|
IStore store = new StoreWrapper(rawStore);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(this, "New store: {0}", rawStore.DisplayName);
|
||||||
|
AccountWrapper account = TryCreateFromRegistry(store);
|
||||||
|
if (account == null)
|
||||||
|
{
|
||||||
|
// Add it to the cache so it is not evaluated again.
|
||||||
|
_accountsByStoreId.Add(store.StoreID, null);
|
||||||
|
Logger.Instance.Trace(this, "Not an account store: {0}", store.DisplayName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(this, "New account store: {0}: {1}", store.DisplayName, account);
|
||||||
|
// Account has taken ownership of the store
|
||||||
|
store = null;
|
||||||
|
OnAccountDiscovered(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Event_StoreAdded Exception: {0}", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
store?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckAccountsRemoved()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Collect all the store ids
|
||||||
|
HashSet<string> stores = new HashSet<string>();
|
||||||
|
foreach (NSOutlook.Store store in _item)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stores.Add(store.StoreID);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any relevant ones are removed
|
||||||
|
List<KeyValuePair<string, AccountWrapper>> removed = new List<KeyValuePair<string, AccountWrapper>>();
|
||||||
|
foreach (KeyValuePair<string, AccountWrapper> account in _accountsByStoreId)
|
||||||
|
{
|
||||||
|
if (!stores.Contains(account.Key))
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(this, "Store not found: {0} - {1}", account.Value, account.Key);
|
||||||
|
removed.Add(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any removed stores
|
||||||
|
foreach (KeyValuePair<string, AccountWrapper> remove in removed)
|
||||||
|
{
|
||||||
|
Logger.Instance.Debug(this, "Account removed: {0} - {1}", remove.Value, remove.Key);
|
||||||
|
_accountsByStoreId.Remove(remove.Key);
|
||||||
|
if (remove.Value != null)
|
||||||
|
{
|
||||||
|
_accountsBySmtp.Remove(remove.Value.SmtpAddress);
|
||||||
|
OnAccountRemoved(remove.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Error(this, "Exception in CheckAccountsRemoved: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public interface
|
||||||
|
|
||||||
|
public IStore AddFileStore(string path)
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.NameSpace session = com.Add(_item.Session);
|
||||||
|
|
||||||
|
// Add the store
|
||||||
|
session.AddStore(path);
|
||||||
|
|
||||||
|
// And fetch it and wrap
|
||||||
|
return Mapping.Wrap(_item[_item.Count]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<IStore> GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (NSOutlook.Store store in _item)
|
||||||
|
{
|
||||||
|
yield return Mapping.Wrap(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
foreach (NSOutlook.Store store in _item)
|
||||||
|
{
|
||||||
|
yield return Mapping.Wrap(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IAccount> Accounts
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _accountsBySmtp.Values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Registry
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the AccountWrapper for the store, from the registry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="store">The store. Ownership is transferred to the AccountWrapper. If the account is not created, the store is NOT disposed</param>
|
||||||
|
/// <returns>The AccountWrapper, or null if no account is associated with the store</returns>
|
||||||
|
private AccountWrapper TryCreateFromRegistry(IStore store)
|
||||||
|
{
|
||||||
|
using (RegistryKey baseKey = FindRegistryKey(store))
|
||||||
|
{
|
||||||
|
if (baseKey == null)
|
||||||
|
return null;
|
||||||
|
AccountWrapper account = new AccountWrapper(baseKey.Name, store);
|
||||||
|
Register(account);
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Register(AccountWrapper account)
|
||||||
|
{
|
||||||
|
// Register the new account
|
||||||
|
_accountsBySmtp.Add(account.SmtpAddress, account);
|
||||||
|
_accountsByStoreId.Add(account.StoreID, account);
|
||||||
|
Logger.Instance.Trace(this, "Account registered: {0} -> {1}", account.DisplayName, account.StoreID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds the registry key for the account associated with the store.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The registry key, or null if it cannot be found</returns>
|
||||||
|
private RegistryKey FindRegistryKey(IStore store)
|
||||||
|
{
|
||||||
|
// Find the registry key by store id
|
||||||
|
using (RegistryKey key = OpenBaseKey())
|
||||||
|
{
|
||||||
|
if (key != null)
|
||||||
|
{
|
||||||
|
foreach (string subkey in key.GetSubKeyNames())
|
||||||
|
{
|
||||||
|
RegistryKey accountKey = key.OpenSubKey(subkey);
|
||||||
|
string storeId = AccountWrapper.GetStoreId(accountKey.Name);
|
||||||
|
if (storeId != null && storeId == store.StoreID)
|
||||||
|
{
|
||||||
|
return accountKey;
|
||||||
|
}
|
||||||
|
accountKey.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryKey OpenBaseKey()
|
||||||
|
{
|
||||||
|
NSOutlook.NameSpace session = _item.Session;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string path = string.Format(OutlookConstants.REG_SUBKEY_ACCOUNTS, session.CurrentProfileName);
|
||||||
|
return OutlookRegistryUtils.OpenOutlookKey(path);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/// Copyright 2017 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;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
|
{
|
||||||
|
class SyncObjectWrapper : ComWrapper<NSOutlook.SyncObject>, ISyncObject
|
||||||
|
{
|
||||||
|
public SyncObjectWrapper(NSOutlook.SyncObject item) : base(item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public string Name { get { return _item.Name; } }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_item.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_item.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event NSOutlook.SyncObjectEvents_OnErrorEventHandler OnError
|
||||||
|
{
|
||||||
|
add { _item.OnError += value; }
|
||||||
|
remove { _item.OnError -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.SyncObjectEvents_ProgressEventHandler Progress
|
||||||
|
{
|
||||||
|
add { _item.Progress += value; }
|
||||||
|
remove { _item.Progress -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.SyncObjectEvents_SyncEndEventHandler SyncEnd
|
||||||
|
{
|
||||||
|
add { _item.SyncEnd += value; }
|
||||||
|
remove { _item.SyncEnd -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event NSOutlook.SyncObjectEvents_SyncStartEventHandler SyncStart
|
||||||
|
{
|
||||||
|
add { _item.SyncStart += value; }
|
||||||
|
remove { _item.SyncStart -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -15,31 +15,44 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
public class TaskItemWrapper : OutlookWrapper<TaskItem>, ITaskItem
|
class TaskItemWrapper : OutlookItemWrapper<NSOutlook.TaskItem>, ITaskItem
|
||||||
{
|
{
|
||||||
internal TaskItemWrapper(TaskItem item)
|
internal TaskItemWrapper(NSOutlook.TaskItem item)
|
||||||
:
|
:
|
||||||
base(item)
|
base(item)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PropertyAccessor GetPropertyAccessor()
|
#region Wrapper methods
|
||||||
|
|
||||||
|
protected override NSOutlook.UserProperties GetUserProperties()
|
||||||
|
{
|
||||||
|
return _item.UserProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||||
{
|
{
|
||||||
return _item.PropertyAccessor;
|
return _item.PropertyAccessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() { return "Task: " + Subject; }
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Task:" + Subject;
|
||||||
|
}
|
||||||
|
|
||||||
#region Properties
|
#endregion
|
||||||
|
|
||||||
|
#region IItem implementation
|
||||||
|
|
||||||
public string Body
|
public string Body
|
||||||
{
|
{
|
||||||
@ -50,48 +63,75 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
public string Subject
|
public string Subject
|
||||||
{
|
{
|
||||||
get { return _item.Subject; }
|
get { return _item.Subject; }
|
||||||
set { throw new NotSupportedException(); }
|
set { _item.Subject = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
|
||||||
// TODO: release needed
|
|
||||||
public string StoreId { get { return _item.Parent?.Store?.StoreID; } }
|
|
||||||
public string StoreDisplayName { get { return _item.Parent?.Store?.DisplayName; } }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete() { _item.Delete(); }
|
|
||||||
public void Save() { _item.Save(); }
|
public void Save() { _item.Save(); }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IBase implementation
|
||||||
|
|
||||||
|
public string EntryID { get { return _item.EntryID; } }
|
||||||
|
|
||||||
public IFolder Parent
|
public IFolder Parent
|
||||||
{
|
|
||||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
|
||||||
}
|
|
||||||
public string ParentEntryId
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Folder parent = _item.Parent;
|
// The wrapper manages the returned folder
|
||||||
try
|
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||||
{
|
|
||||||
return parent?.EntryID;
|
|
||||||
}
|
}
|
||||||
finally
|
}
|
||||||
|
|
||||||
|
public string ParentEntryID
|
||||||
{
|
{
|
||||||
ComRelease.Release(parent);
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return parent?.EntryID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EntryId { get { return _item.EntryID; } }
|
public IStore GetStore()
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
return Mapping.Wrap(parent?.Store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreID
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StoreDisplayName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using (ComRelease com = new ComRelease())
|
||||||
|
{
|
||||||
|
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||||
|
NSOutlook.Store store = com.Add(parent?.Store);
|
||||||
|
return store.StoreID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Delete() { _item.Delete(); }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,76 +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;
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
|
||||||
{
|
|
||||||
class UserPropertyWrapper<PropType> : IUserProperty<PropType>
|
|
||||||
{
|
|
||||||
private readonly UserProperty _prop;
|
|
||||||
|
|
||||||
private UserPropertyWrapper(UserProperty prop)
|
|
||||||
{
|
|
||||||
this._prop = prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IUserProperty implementation
|
|
||||||
|
|
||||||
public PropType Value
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (typeof(PropType).IsEnum)
|
|
||||||
return typeof(PropType).GetEnumValues().GetValue(_prop.Value);
|
|
||||||
return _prop.Value;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (typeof(PropType).IsEnum)
|
|
||||||
{
|
|
||||||
int i = Array.FindIndex(typeof(PropType).GetEnumNames(), n => n.Equals(value.ToString()));
|
|
||||||
_prop.Value = typeof(PropType).GetEnumValues().GetValue(i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_prop.Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Helpers
|
|
||||||
|
|
||||||
internal static IUserProperty<PropType> Get(UserProperties userProperties, string name, bool create)
|
|
||||||
{
|
|
||||||
UserProperty prop = userProperties.Find(name, true);
|
|
||||||
if (prop == null)
|
|
||||||
{
|
|
||||||
if (!create)
|
|
||||||
return null;
|
|
||||||
prop = userProperties.Add(name, Mapping.OutlookPropertyType<PropType>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UserPropertyWrapper<PropType>(prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
66
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Wrappers.cs
Normal file
66
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/Wrappers.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/// Copyright 2017 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 Acacia.Stubs.OutlookWrappers;
|
||||||
|
using Acacia.Utils;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return Mapping.WrapOrDefault<IFolder>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static FolderType Wrap<FolderType>(this NSOutlook.MAPIFolder folder)
|
||||||
|
where FolderType : IFolder
|
||||||
|
{
|
||||||
|
if (typeof(FolderType) == typeof(IFolder))
|
||||||
|
{
|
||||||
|
return (FolderType)(IFolder)new FolderWrapper(folder);
|
||||||
|
}
|
||||||
|
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||||
|
{
|
||||||
|
return (FolderType)(IFolder)new AddressBookWrapper(folder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ComRelease.Release(folder);
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WrapType Wrap<WrapType>(this object o, bool mustRelease = true)
|
||||||
|
where WrapType : IBase
|
||||||
|
{
|
||||||
|
return Mapping.Wrap<WrapType>(o, mustRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WrapType WrapOrDefault<WrapType>(this object o, bool mustRelease = true)
|
||||||
|
where WrapType : IBase
|
||||||
|
{
|
||||||
|
return Mapping.WrapOrDefault<WrapType>(o, mustRelease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,8 +19,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Outlook = Microsoft.Office.Interop.Outlook;
|
|
||||||
using Office = Microsoft.Office.Core;
|
|
||||||
using Acacia.Features;
|
using Acacia.Features;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
@ -29,27 +27,23 @@ using Acacia.UI;
|
|||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Acacia.UI.Outlook;
|
using Acacia.UI.Outlook;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Reflection;
|
||||||
|
using Acacia.Native;
|
||||||
|
using Acacia.Stubs;
|
||||||
|
using Acacia.Stubs.OutlookWrappers;
|
||||||
|
|
||||||
namespace Acacia
|
namespace Acacia
|
||||||
{
|
{
|
||||||
public partial class ThisAddIn
|
public partial class ThisAddIn
|
||||||
{
|
{
|
||||||
|
public static IAddIn Instance
|
||||||
public static ThisAddIn Instance
|
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Control _dispatcher;
|
|
||||||
|
|
||||||
public void InvokeUI(Action action)
|
|
||||||
{
|
|
||||||
// [ZP-992] For some reason using the dispatcher causes a deadlock
|
|
||||||
// since switching to UI-chunked tasks. Running directly works.
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Features
|
#region Features
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -69,15 +63,20 @@ namespace Acacia
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeatureType GetFeature<FeatureType>()
|
private MailEvents _mailEvents;
|
||||||
where FeatureType : Feature
|
public MailEvents MailEvents
|
||||||
{
|
{
|
||||||
foreach(Feature feature in Features)
|
get
|
||||||
{
|
{
|
||||||
if (feature is FeatureType)
|
if (_mailEvents == null)
|
||||||
return (FeatureType)feature;
|
{
|
||||||
|
if (GlobalOptions.INSTANCE.HookItemEvents)
|
||||||
|
{
|
||||||
|
_mailEvents = new MailEvents(Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _mailEvents;
|
||||||
}
|
}
|
||||||
return default(FeatureType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Startup / Shutdown
|
#region Startup / Shutdown
|
||||||
@ -100,16 +99,12 @@ namespace Acacia
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance = this;
|
Instance = new AddInWrapper(this);
|
||||||
|
|
||||||
// Set the culture info from Outlook's language setting rather than the OS setting
|
// Set the culture info from Outlook's language setting rather than the OS setting
|
||||||
int lcid = Application.LanguageSettings.get_LanguageID(Office.MsoAppLanguageID.msoLanguageIDUI);
|
int lcid = Application.LanguageSettings.get_LanguageID(Microsoft.Office.Core.MsoAppLanguageID.msoLanguageIDUI);
|
||||||
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid);
|
Thread.CurrentThread.CurrentUICulture = new CultureInfo(lcid);
|
||||||
|
|
||||||
// Create a dispatcher
|
|
||||||
_dispatcher = new Control();
|
|
||||||
_dispatcher.CreateControl();
|
|
||||||
|
|
||||||
// The synchronization context is needed to allow background tasks to jump back to the UI thread.
|
// The synchronization context is needed to allow background tasks to jump back to the UI thread.
|
||||||
// It's null in older versions of .Net, this fixes that
|
// It's null in older versions of .Net, this fixes that
|
||||||
if (SynchronizationContext.Current == null)
|
if (SynchronizationContext.Current == null)
|
||||||
@ -118,7 +113,7 @@ namespace Acacia
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the watcher
|
// Create the watcher
|
||||||
Watcher = new ZPushWatcher(Application);
|
Watcher = new ZPushWatcher(Instance);
|
||||||
OutlookUI.Watcher = Watcher;
|
OutlookUI.Watcher = Watcher;
|
||||||
|
|
||||||
// Allow to features to register whatever they need
|
// Allow to features to register whatever they need
|
||||||
@ -151,11 +146,17 @@ namespace Acacia
|
|||||||
|
|
||||||
// Start watching events
|
// Start watching events
|
||||||
if (DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED))
|
if (DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED))
|
||||||
|
{
|
||||||
|
((AddInWrapper)Instance).Start();
|
||||||
Watcher.Start();
|
Watcher.Start();
|
||||||
|
}
|
||||||
|
|
||||||
// Done
|
// Done
|
||||||
Logger.Instance.Debug(this, "Startup done");
|
Logger.Instance.Debug(this, "Startup done");
|
||||||
Acacia.Features.DebugSupport.Statistics.StartupTime.Stop();
|
Acacia.Features.DebugSupport.Statistics.StartupTime.Stop();
|
||||||
|
foreach (Feature feature in Features)
|
||||||
|
feature.AfterStartup();
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
{
|
{
|
||||||
@ -172,6 +173,7 @@ namespace Acacia
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// TODO: is any management of Pages needed here?
|
||||||
Pages.Add(new SettingsPage(Features.ToArray()), Properties.Resources.ThisAddIn_Title);
|
Pages.Add(new SettingsPage(Features.ToArray()), Properties.Resources.ThisAddIn_Title);
|
||||||
}
|
}
|
||||||
catch(System.Exception e)
|
catch(System.Exception e)
|
||||||
|
@ -224,24 +224,23 @@ namespace Acacia.UI
|
|||||||
public List<GABUser> Lookup(string text, int max)
|
public List<GABUser> Lookup(string text, int max)
|
||||||
{
|
{
|
||||||
// Begin GAB lookup, search on full name or username
|
// Begin GAB lookup, search on full name or username
|
||||||
ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>();
|
using (ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>())
|
||||||
|
{
|
||||||
ISearchOperator oper = search.AddOperator(SearchOperator.Or);
|
ISearchOperator oper = search.AddOperator(SearchOperator.Or);
|
||||||
oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%");
|
oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%");
|
||||||
oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%");
|
oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%");
|
||||||
|
|
||||||
// Fetch the results up to the limit.
|
// Fetch the results up to the limit.
|
||||||
// TODO: make limit a property
|
// TODO: make limit a property?
|
||||||
List<GABUser> users = new List<GABUser>();
|
List<GABUser> users = new List<GABUser>();
|
||||||
foreach (IContactItem result in search.Search(max))
|
foreach (IContactItem result in search.Search(max))
|
||||||
{
|
|
||||||
using (result)
|
|
||||||
{
|
{
|
||||||
users.Add(new GABUser(result.FullName, result.CustomerID));
|
users.Add(new GABUser(result.FullName, result.CustomerID));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public GABUser LookupExact(string username)
|
public GABUser LookupExact(string username)
|
||||||
{
|
{
|
||||||
@ -252,15 +251,13 @@ namespace Acacia.UI
|
|||||||
search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, username);
|
search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, username);
|
||||||
|
|
||||||
// Fetch the result, if any.
|
// Fetch the result, if any.
|
||||||
|
// TODO: make a SearchOne method?
|
||||||
List<GABUser> users = new List<GABUser>();
|
List<GABUser> users = new List<GABUser>();
|
||||||
foreach (IContactItem result in search.Search(1))
|
foreach (IContactItem result in search.Search(1))
|
||||||
{
|
|
||||||
using (result)
|
|
||||||
{
|
{
|
||||||
return new GABUser(result.FullName, result.CustomerID);
|
return new GABUser(result.FullName, result.CustomerID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return new GABUser(username);
|
return new GABUser(username);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
|
||||||
|
using Acacia.Stubs;
|
||||||
|
using Acacia.Utils;
|
||||||
|
/// Copyright 2016 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -13,7 +16,6 @@
|
|||||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Core;
|
using Microsoft.Office.Core;
|
||||||
using stdole;
|
using stdole;
|
||||||
using System;
|
using System;
|
||||||
@ -35,105 +37,19 @@ namespace Acacia.UI.Outlook
|
|||||||
{
|
{
|
||||||
public ImageList Images { get; private set; }
|
public ImageList Images { get; private set; }
|
||||||
|
|
||||||
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
|
||||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
|
||||||
|
|
||||||
private Bitmap GetBitmapFromHBitmap2(IntPtr nativeHBitmap)
|
|
||||||
{
|
|
||||||
|
|
||||||
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap);
|
|
||||||
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32)
|
|
||||||
return bmp;
|
|
||||||
|
|
||||||
// Special handling is required to convert a bitmap with alpha channel, FromHBitmap doesn't
|
|
||||||
// set the correct pixel format
|
|
||||||
Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
|
||||||
BitmapData bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
|
||||||
Bitmap bmp2 = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb);
|
|
||||||
BitmapData bmpData2 = bmp2.LockBits(bmBounds, ImageLockMode.WriteOnly, bmp2.PixelFormat);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int y = 0; y < bmp.Height; ++y)
|
|
||||||
{
|
|
||||||
IntPtr target = bmpData2.Scan0 + bmpData2.Stride * y;
|
|
||||||
IntPtr source = bmpData.Scan0 + bmpData.Stride * y;
|
|
||||||
CopyMemory(target, source, (uint)Math.Abs(bmpData2.Stride));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bmp2.UnlockBits(bmpData2);
|
|
||||||
bmp.UnlockBits(bmpData);
|
|
||||||
}
|
|
||||||
return bmp2;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
|
|
||||||
{
|
|
||||||
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap);
|
|
||||||
|
|
||||||
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32)
|
|
||||||
return bmp;
|
|
||||||
|
|
||||||
BitmapData bmpData;
|
|
||||||
|
|
||||||
if (IsAlphaBitmap(bmp, out bmpData))
|
|
||||||
return GetlAlphaBitmapFromBitmapData(bmpData);
|
|
||||||
|
|
||||||
return bmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bitmap GetlAlphaBitmapFromBitmapData(BitmapData bmpData)
|
|
||||||
{
|
|
||||||
return new Bitmap(
|
|
||||||
bmpData.Width,
|
|
||||||
bmpData.Height,
|
|
||||||
bmpData.Stride,
|
|
||||||
PixelFormat.Format32bppArgb,
|
|
||||||
bmpData.Scan0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsAlphaBitmap(Bitmap bmp, out BitmapData bmpData)
|
|
||||||
{
|
|
||||||
Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
|
||||||
|
|
||||||
bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (int y = 0; y <= bmpData.Height - 1; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x <= bmpData.Width - 1; x++)
|
|
||||||
{
|
|
||||||
Color pixelColor = Color.FromArgb(
|
|
||||||
Marshal.ReadInt32(bmpData.Scan0, (bmpData.Stride * y) + (4 * x)));
|
|
||||||
|
|
||||||
if (pixelColor.A > 0 & pixelColor.A < 255)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bmp.UnlockBits(bmpData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public OutlookImageList(params string[] icons)
|
public OutlookImageList(params string[] icons)
|
||||||
{
|
{
|
||||||
Images = new ImageList();
|
Images = new ImageList();
|
||||||
Images.ColorDepth = ColorDepth.Depth32Bit;
|
Images.ColorDepth = ColorDepth.Depth32Bit;
|
||||||
Images.ImageSize = new Size(16, 16);
|
Images.ImageSize = new Size(16, 16);
|
||||||
|
|
||||||
CommandBars cmdBars = ThisAddIn.Instance.Application.ActiveWindow().CommandBars;
|
using (IExplorer explorer = ThisAddIn.Instance.GetActiveExplorer())
|
||||||
|
using (ICommandBars cmdBars = explorer.GetCommandBars())
|
||||||
|
{
|
||||||
foreach (string id in icons)
|
foreach (string id in icons)
|
||||||
{
|
{
|
||||||
IPictureDisp pict = cmdBars.GetImageMso(id, Images.ImageSize.Width, Images.ImageSize.Height);
|
Images.Images.Add(cmdBars.GetMso(id).GetImage(Images.ImageSize));
|
||||||
var img = GetBitmapFromHBitmap2(new IntPtr(pict.Handle));
|
}
|
||||||
Images.Images.Add(img);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
@ -23,7 +23,6 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
|
|
||||||
namespace Acacia.UI
|
namespace Acacia.UI
|
||||||
{
|
{
|
||||||
@ -48,19 +47,19 @@ namespace Acacia.UI
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return ThisAddIn.Instance.Application;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public OlObjectClass Class
|
public Microsoft.Office.Interop.Outlook.OlObjectClass Class
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return OlObjectClass.olApplication;
|
return Microsoft.Office.Interop.Outlook.OlObjectClass.olApplication;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public NameSpace Session
|
public Microsoft.Office.Interop.Outlook.NameSpace Session
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -68,7 +67,7 @@ namespace Acacia.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic PropertyPageSite.Parent
|
dynamic Microsoft.Office.Interop.Outlook.PropertyPageSite.Parent
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -25,11 +25,12 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Acacia.Features;
|
using Acacia.Features;
|
||||||
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
|
||||||
namespace Acacia.UI
|
namespace Acacia.UI
|
||||||
{
|
{
|
||||||
[ComVisible(true)]
|
[ComVisible(true)]
|
||||||
public partial class SettingsPage : UserControl, Microsoft.Office.Interop.Outlook.PropertyPage
|
public partial class SettingsPage : UserControl, NSOutlook.PropertyPage
|
||||||
{
|
{
|
||||||
private readonly Dictionary<FeatureSettings, bool> _featuresDirty = new Dictionary<FeatureSettings, bool>();
|
private readonly Dictionary<FeatureSettings, bool> _featuresDirty = new Dictionary<FeatureSettings, bool>();
|
||||||
|
|
||||||
@ -78,8 +79,8 @@ namespace Acacia.UI
|
|||||||
Dirty = _featuresDirty.Values.Aggregate((a, b) => a | b);
|
Dirty = _featuresDirty.Values.Aggregate((a, b) => a | b);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Microsoft.Office.Interop.Outlook.PropertyPageSite _propertyPageSite;
|
private NSOutlook.PropertyPageSite _propertyPageSite;
|
||||||
public Microsoft.Office.Interop.Outlook.PropertyPageSite PropertyPageSite
|
public NSOutlook.PropertyPageSite PropertyPageSite
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -96,7 +97,8 @@ namespace Acacia.UI
|
|||||||
System.Reflection.MethodInfo methodInfo = oleObjectType.GetMethod("GetClientSite");
|
System.Reflection.MethodInfo methodInfo = oleObjectType.GetMethod("GetClientSite");
|
||||||
Object propertyPageSite = methodInfo.Invoke(this, null);
|
Object propertyPageSite = methodInfo.Invoke(this, null);
|
||||||
|
|
||||||
_propertyPageSite = (Microsoft.Office.Interop.Outlook.PropertyPageSite)propertyPageSite;
|
// TODO: does this need to be released?
|
||||||
|
_propertyPageSite = (NSOutlook.PropertyPageSite)propertyPageSite;
|
||||||
}
|
}
|
||||||
return _propertyPageSite;
|
return _propertyPageSite;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,12 @@ namespace Acacia.Utils
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Type Remove<Type>(Type t)
|
||||||
|
{
|
||||||
|
objects.Remove(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
foreach (object o in objects)
|
foreach (object o in objects)
|
||||||
@ -55,11 +61,17 @@ namespace Acacia.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Release(params object[] objs)
|
||||||
|
{
|
||||||
|
foreach (object o in objs)
|
||||||
|
Release(o);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Release(object o)
|
public static void Release(object o)
|
||||||
{
|
{
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return;
|
return;
|
||||||
if (o == null)
|
if (o == null || !Marshal.IsComObject(o))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Logger.Instance.IsLevelEnabled(LogLevel.TraceExtra))
|
if (Logger.Instance.IsLevelEnabled(LogLevel.TraceExtra))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
/// Copyright 2017 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -15,7 +15,6 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Features.DebugSupport;
|
using Acacia.Features.DebugSupport;
|
||||||
using Acacia.Utils;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -23,15 +22,13 @@ using System.Text;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Utils
|
||||||
{
|
{
|
||||||
public abstract class DisposableWrapper : IDisposable
|
abstract public class DisposableWrapper : IDisposable
|
||||||
{
|
{
|
||||||
|
private static Dictionary<Type, int> typeCounts = new Dictionary<Type, int>();
|
||||||
|
|
||||||
/// <summary>
|
protected DisposableWrapper()
|
||||||
/// Creates a wrapper.
|
|
||||||
/// </summary>
|
|
||||||
internal DisposableWrapper()
|
|
||||||
{
|
{
|
||||||
Interlocked.Increment(ref Statistics.CreatedWrappers);
|
Interlocked.Increment(ref Statistics.CreatedWrappers);
|
||||||
this._createdTrace = new System.Diagnostics.StackTrace();
|
this._createdTrace = new System.Diagnostics.StackTrace();
|
||||||
@ -43,9 +40,12 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
|
Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
|
||||||
Dispose();
|
// Dispose, but don't count auto disposals, so the stats show it.
|
||||||
// Don't count auto disposals
|
DoRelease();
|
||||||
Interlocked.Decrement(ref Statistics.DisposedWrappers);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--typeCounts[GetType()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +56,11 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
{
|
{
|
||||||
if (!_isDisposed)
|
if (!_isDisposed)
|
||||||
{
|
{
|
||||||
|
if (!typeCounts.ContainsKey(GetType()))
|
||||||
|
typeCounts.Add(GetType(), 1);
|
||||||
|
else
|
||||||
|
++typeCounts[GetType()];
|
||||||
|
|
||||||
Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace());
|
Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace());
|
||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
Interlocked.Increment(ref Statistics.DisposedWrappers);
|
Interlocked.Increment(ref Statistics.DisposedWrappers);
|
||||||
@ -63,12 +68,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool MustRelease
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract protected void DoRelease();
|
abstract protected void DoRelease();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -28,17 +28,19 @@ namespace Acacia.Utils
|
|||||||
{
|
{
|
||||||
public static class FolderUtils
|
public static class FolderUtils
|
||||||
{
|
{
|
||||||
public static OutlookConstants.SyncType GetFolderSyncType(IFolder folder, bool orig = false)
|
public static OutlookConstants.SyncType? GetFolderSyncType(IFolder folder, bool orig = false)
|
||||||
{
|
{
|
||||||
if (orig)
|
if (orig)
|
||||||
{
|
{
|
||||||
string type = (string)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE_ORIG);
|
string type = (string)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE_ORIG);
|
||||||
|
if (string.IsNullOrEmpty(type))
|
||||||
|
return null;
|
||||||
return (OutlookConstants.SyncType)int.Parse(type);
|
return (OutlookConstants.SyncType)int.Parse(type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int type = (int)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE);
|
int? type = (int?)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE);
|
||||||
return (OutlookConstants.SyncType)type;
|
return (OutlookConstants.SyncType?)type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs
Normal file
63
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/ImageUtils.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/// Copyright 2017 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.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Utils
|
||||||
|
{
|
||||||
|
public static class ImageUtils
|
||||||
|
{
|
||||||
|
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
|
||||||
|
private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||||
|
|
||||||
|
public static Bitmap GetBitmapFromHBitmap(IntPtr nativeHBitmap)
|
||||||
|
{
|
||||||
|
|
||||||
|
Bitmap bmp = Bitmap.FromHbitmap(nativeHBitmap);
|
||||||
|
if (Bitmap.GetPixelFormatSize(bmp.PixelFormat) < 32)
|
||||||
|
return bmp;
|
||||||
|
|
||||||
|
// Special handling is required to convert a bitmap with alpha channel, FromHBitmap doesn't
|
||||||
|
// set the correct pixel format
|
||||||
|
Rectangle bmBounds = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||||
|
BitmapData bmpData = bmp.LockBits(bmBounds, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||||
|
Bitmap bmp2 = new Bitmap(bmpData.Width, bmpData.Height, PixelFormat.Format32bppArgb);
|
||||||
|
BitmapData bmpData2 = bmp2.LockBits(bmBounds, ImageLockMode.WriteOnly, bmp2.PixelFormat);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int y = 0; y < bmp.Height; ++y)
|
||||||
|
{
|
||||||
|
IntPtr target = bmpData2.Scan0 + bmpData2.Stride * y;
|
||||||
|
IntPtr source = bmpData.Scan0 + bmpData.Stride * y;
|
||||||
|
CopyMemory(target, source, (uint)Math.Abs(bmpData2.Stride));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
bmp2.UnlockBits(bmpData2);
|
||||||
|
bmp.UnlockBits(bmpData);
|
||||||
|
}
|
||||||
|
return bmp2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@
|
|||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -47,20 +46,16 @@ namespace Acacia.Utils
|
|||||||
public event MailResponseEventHandler Respond;
|
public event MailResponseEventHandler Respond;
|
||||||
|
|
||||||
public event MailResponseEventHandler Reply;
|
public event MailResponseEventHandler Reply;
|
||||||
private void OnReply(MailItem mail, MailItem response)
|
private void OnReply(IMailItem mail, IMailItem response)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((Reply != null || Respond != null) && mail != null)
|
if ((Reply != null || Respond != null) && mail != null && response != null)
|
||||||
{
|
|
||||||
using (IMailItem mailWrapped = Mapping.Wrap<IMailItem>(mail, false),
|
|
||||||
responseWrapped = Mapping.Wrap<IMailItem>(response))
|
|
||||||
{
|
{
|
||||||
if (Reply != null)
|
if (Reply != null)
|
||||||
Reply(mailWrapped, responseWrapped);
|
Reply(mail, response);
|
||||||
if (Respond != null)
|
if (Respond != null)
|
||||||
Respond(mailWrapped, responseWrapped);
|
Respond(mail, response);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
@ -70,20 +65,16 @@ namespace Acacia.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public event MailResponseEventHandler ReplyAll;
|
public event MailResponseEventHandler ReplyAll;
|
||||||
private void OnReplyAll(MailItem mail, MailItem response)
|
private void OnReplyAll(IMailItem mail, IMailItem response)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((ReplyAll != null || Respond != null) && mail != null)
|
if ((ReplyAll != null || Respond != null) && mail != null && response != null)
|
||||||
{
|
|
||||||
using (IMailItem mailWrapped = Mapping.Wrap<IMailItem>(mail, false),
|
|
||||||
responseWrapped = Mapping.Wrap<IMailItem>(response))
|
|
||||||
{
|
{
|
||||||
if (ReplyAll != null)
|
if (ReplyAll != null)
|
||||||
ReplyAll(mailWrapped, responseWrapped);
|
ReplyAll(mail, response);
|
||||||
if (Respond != null)
|
if (Respond != null)
|
||||||
Respond(mailWrapped, responseWrapped);
|
Respond(mail, response);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
@ -93,20 +84,16 @@ namespace Acacia.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public event MailResponseEventHandler Forward;
|
public event MailResponseEventHandler Forward;
|
||||||
private void OnForward(MailItem mail, MailItem response)
|
private void OnForward(IMailItem mail, IMailItem response)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((Forward != null || Respond != null) && mail != null)
|
if ((Forward != null || Respond != null) && mail != null && response != null)
|
||||||
{
|
|
||||||
using (IMailItem mailWrapped = Mapping.Wrap<IMailItem>(mail, false),
|
|
||||||
responseWrapped = Mapping.Wrap<IMailItem>(response))
|
|
||||||
{
|
{
|
||||||
if (Forward != null)
|
if (Forward != null)
|
||||||
Forward(mailWrapped, responseWrapped);
|
Forward(mail, response);
|
||||||
if (Respond != null)
|
if (Respond != null)
|
||||||
Respond(mailWrapped, responseWrapped);
|
Respond(mail, response);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
@ -116,16 +103,13 @@ namespace Acacia.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public event MailEventHandler Read;
|
public event MailEventHandler Read;
|
||||||
private void OnRead(MailItem mail)
|
private void OnRead(IMailItem mail)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Read != null && mail != null)
|
if (Read != null && mail != null)
|
||||||
{
|
{
|
||||||
using (IMailItem wrapped = Mapping.Wrap<IMailItem>(mail, false))
|
Read(mail);
|
||||||
{
|
|
||||||
Read(wrapped);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
@ -135,17 +119,13 @@ namespace Acacia.Utils
|
|||||||
}
|
}
|
||||||
|
|
||||||
public event CancellableItemEventHandler BeforeDelete;
|
public event CancellableItemEventHandler BeforeDelete;
|
||||||
private void OnBeforeDelete(object item, ref bool cancel)
|
private void OnBeforeDelete(IItem item, ref bool cancel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (BeforeDelete != null && item != null)
|
if (BeforeDelete != null && item != null)
|
||||||
{
|
{
|
||||||
using (IItem wrapped = Mapping.Wrap<IItem>(item, false))
|
BeforeDelete(item, ref cancel);
|
||||||
{
|
|
||||||
if (wrapped != null)
|
|
||||||
BeforeDelete(wrapped, ref cancel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(System.Exception e)
|
catch(System.Exception e)
|
||||||
@ -156,17 +136,13 @@ namespace Acacia.Utils
|
|||||||
|
|
||||||
// TODO: should this be CancellableMailItemEventHandler?
|
// TODO: should this be CancellableMailItemEventHandler?
|
||||||
public event CancellableItemEventHandler Write;
|
public event CancellableItemEventHandler Write;
|
||||||
private void OnWrite(object item, ref bool cancel)
|
private void OnWrite(IItem item, ref bool cancel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Write != null && item != null)
|
if (Write != null && item != null)
|
||||||
{
|
{
|
||||||
using (IItem wrapped = Mapping.Wrap<IItem>(item, false))
|
Write(item, ref cancel);
|
||||||
{
|
|
||||||
if (wrapped != null)
|
|
||||||
Write(wrapped, ref cancel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (System.Exception e)
|
||||||
@ -199,39 +175,46 @@ namespace Acacia.Utils
|
|||||||
|
|
||||||
#region Implementation
|
#region Implementation
|
||||||
|
|
||||||
public MailEvents(Application app)
|
public MailEvents(IAddIn app)
|
||||||
{
|
{
|
||||||
app.ItemLoad += OnItemLoad;
|
app.ItemLoad += OnItemLoad;
|
||||||
app.ItemSend += OnItemSend;
|
app.ItemSend += OnItemSend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnItemLoad(object item)
|
private void OnItemLoad(object item)
|
||||||
{
|
{
|
||||||
ItemEvents_10_Event hasEvents = item as ItemEvents_10_Event;
|
IItem wrapped = Wrappers.Wrap<IItem>(item, false);
|
||||||
if (hasEvents != null)
|
// TODO: only register for desired types
|
||||||
|
if (wrapped != null)
|
||||||
{
|
{
|
||||||
new MailEventHooker(hasEvents, this);
|
new MailEventHooker(wrapped, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MailEventHooker
|
private class MailEventHooker : DisposableWrapper
|
||||||
{
|
{
|
||||||
private readonly ItemEvents_10_Event item;
|
private IItem _item;
|
||||||
private readonly MailEvents events;
|
private readonly MailEvents _events;
|
||||||
|
|
||||||
public MailEventHooker(ItemEvents_10_Event item, MailEvents events)
|
public MailEventHooker(IItem item, MailEvents events)
|
||||||
{
|
{
|
||||||
this.item = item;
|
this._item = item;
|
||||||
this.events = events;
|
this._events = events;
|
||||||
HookEvents(true);
|
HookEvents(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
_item.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
private void HookEvents(bool add)
|
private void HookEvents(bool add)
|
||||||
{
|
{
|
||||||
ItemEvents_10_Event events = this.item;
|
using (IItemEvents events = _item.GetEvents())
|
||||||
|
{
|
||||||
if (add)
|
if (add)
|
||||||
{
|
{
|
||||||
|
|
||||||
events.BeforeDelete += HandleBeforeDelete;
|
events.BeforeDelete += HandleBeforeDelete;
|
||||||
events.Forward += HandleForward;
|
events.Forward += HandleForward;
|
||||||
events.Read += HandleRead;
|
events.Read += HandleRead;
|
||||||
@ -251,41 +234,43 @@ namespace Acacia.Utils
|
|||||||
events.Write -= HandleWrite;
|
events.Write -= HandleWrite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleBeforeDelete(object item, ref bool cancel)
|
private void HandleBeforeDelete(object item, ref bool cancel)
|
||||||
{
|
{
|
||||||
events.OnBeforeDelete(item, ref cancel);
|
_events.OnBeforeDelete(item.WrapOrDefault<IItem>(), ref cancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleForward(object response, ref bool cancel)
|
private void HandleForward(object response, ref bool cancel)
|
||||||
{
|
{
|
||||||
events.OnForward(item as MailItem, response as MailItem);
|
_events.OnForward(_item as IMailItem, response.WrapOrDefault<IMailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleRead()
|
private void HandleRead()
|
||||||
{
|
{
|
||||||
events.OnRead(item as MailItem);
|
_events.OnRead(_item as IMailItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleReply(object response, ref bool cancel)
|
private void HandleReply(object response, ref bool cancel)
|
||||||
{
|
{
|
||||||
events.OnReply(item as MailItem, response as MailItem);
|
_events.OnReply(_item as IMailItem, response.WrapOrDefault<IMailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleReplyAll(object response, ref bool cancel)
|
private void HandleReplyAll(object response, ref bool cancel)
|
||||||
{
|
{
|
||||||
events.OnReplyAll(item as MailItem, response as MailItem);
|
_events.OnReplyAll(_item as IMailItem, response.WrapOrDefault<IMailItem>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUnload()
|
private void HandleUnload()
|
||||||
{
|
{
|
||||||
// All events must be unhooked on unload, otherwise a resource leak is created.
|
// All events must be unhooked on unload, otherwise a resource leak is created.
|
||||||
HookEvents(false);
|
HookEvents(false);
|
||||||
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleWrite(ref bool cancel)
|
private void HandleWrite(ref bool cancel)
|
||||||
{
|
{
|
||||||
events.OnWrite(item, ref cancel);
|
_events.OnWrite(_item, ref cancel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace Acacia.Utils
|
|||||||
public static RegistryKey OpenOutlookKey(string suffix = null, RegistryKeyPermissionCheck permissions = RegistryKeyPermissionCheck.Default)
|
public static RegistryKey OpenOutlookKey(string suffix = null, RegistryKeyPermissionCheck permissions = RegistryKeyPermissionCheck.Default)
|
||||||
{
|
{
|
||||||
// Determine the base path
|
// Determine the base path
|
||||||
string[] versionParts = ThisAddIn.Instance.Application.Version.Split('.');
|
string[] versionParts = ThisAddIn.Instance.Version.Split('.');
|
||||||
string versionString = versionParts[0] + "." + versionParts[1];
|
string versionString = versionParts[0] + "." + versionParts[1];
|
||||||
string baseKeyPath = string.Format(OutlookConstants.REG_KEY_BASE, versionString);
|
string baseKeyPath = string.Format(OutlookConstants.REG_KEY_BASE, versionString);
|
||||||
return RegistryUtil.OpenKeyImpl(baseKeyPath, suffix, false, permissions);
|
return RegistryUtil.OpenKeyImpl(baseKeyPath, suffix, false, permissions);
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Features;
|
using Acacia.Features;
|
||||||
|
using Acacia.Features.DebugSupport;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace Acacia.Utils
|
namespace Acacia.Utils
|
||||||
@ -64,10 +66,29 @@ namespace Acacia.Utils
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TaskExecutor
|
public abstract class TaskExecutor
|
||||||
{
|
{
|
||||||
string Name { get; }
|
public abstract string Name { get; }
|
||||||
void ExecuteTask(AcaciaTask task);
|
|
||||||
|
public void AddTask(AcaciaTask task)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref Statistics.StartedTasks);
|
||||||
|
EnqueueTask(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected void EnqueueTask(AcaciaTask task);
|
||||||
|
|
||||||
|
protected void PerformTask(AcaciaTask task)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
task.Execute();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref Statistics.FinishedTasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Tasks
|
public static class Tasks
|
||||||
@ -103,12 +124,12 @@ namespace Acacia.Utils
|
|||||||
|
|
||||||
public static void Task(Feature owner, string name, Action action)
|
public static void Task(Feature owner, string name, Action action)
|
||||||
{
|
{
|
||||||
Executor.ExecuteTask(new AcaciaTask(owner, name, action));
|
Task(new AcaciaTask(owner, name, action));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Task(AcaciaTask task)
|
public static void Task(AcaciaTask task)
|
||||||
{
|
{
|
||||||
Executor.ExecuteTask(task);
|
Executor.AddTask(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
/// Copyright 2016 Kopano b.v.
|
|
||||||
|
using Acacia.Features.DebugSupport;
|
||||||
|
/// Copyright 2016 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// 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,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -13,7 +15,6 @@
|
|||||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -40,15 +41,15 @@ namespace Acacia.Utils
|
|||||||
while (!_tasks.IsCompleted)
|
while (!_tasks.IsCompleted)
|
||||||
{
|
{
|
||||||
AcaciaTask task = _tasks.Take();
|
AcaciaTask task = _tasks.Take();
|
||||||
task.Execute();
|
PerformTask(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExecuteTask(AcaciaTask task)
|
protected override void EnqueueTask(AcaciaTask task)
|
||||||
{
|
{
|
||||||
_tasks.Add(task);
|
_tasks.Add(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get { return "Background"; } }
|
override public string Name { get { return "Background"; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace Acacia.Utils
|
|||||||
{
|
{
|
||||||
AcaciaTask task = _tasks.Dequeue();
|
AcaciaTask task = _tasks.Dequeue();
|
||||||
Logger.Instance.Trace(task.Id, "Beginning task");
|
Logger.Instance.Trace(task.Id, "Beginning task");
|
||||||
task.Execute();
|
PerformTask(task);
|
||||||
Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds);
|
Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds);
|
||||||
// Execute another task if available and we haven't taken too long.
|
// Execute another task if available and we haven't taken too long.
|
||||||
} while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50);
|
} while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50);
|
||||||
@ -99,7 +99,7 @@ namespace Acacia.Utils
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name, for debugging and logging.</param>
|
/// <param name="name">The name, for debugging and logging.</param>
|
||||||
/// <param name="action">The action to execute</param>
|
/// <param name="action">The action to execute</param>
|
||||||
public void ExecuteTask(AcaciaTask task)
|
override protected void EnqueueTask(AcaciaTask task)
|
||||||
{
|
{
|
||||||
if (_init == InitState.Uninitialised)
|
if (_init == InitState.Uninitialised)
|
||||||
{
|
{
|
||||||
@ -112,6 +112,6 @@ namespace Acacia.Utils
|
|||||||
_tasks.Enqueue(task);
|
_tasks.Enqueue(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get { return "MainThread"; } }
|
override public string Name { get { return "MainThread"; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ namespace Acacia.Utils
|
|||||||
{
|
{
|
||||||
public class TasksSynchronous : TaskExecutor
|
public class TasksSynchronous : TaskExecutor
|
||||||
{
|
{
|
||||||
public void ExecuteTask(AcaciaTask task)
|
protected override void EnqueueTask(AcaciaTask task)
|
||||||
{
|
{
|
||||||
task.Execute();
|
PerformTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name { get { return "Synchronous"; } }
|
override public string Name { get { return "Synchronous"; } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -44,5 +44,123 @@ namespace Acacia.Utils
|
|||||||
|
|
||||||
return a.Equals(b);
|
return a.Equals(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Enumeration helpers
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension for a Com enumeration. Disposes the enumerated object and - optionally - the returned elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The object to be enumerated. This will be released.</param>
|
||||||
|
/// <param name="releaseElements">If true (the default), elements will also be released.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<T> ComEnum<T>(this IEnumerable<T> source, bool releaseElements = true)
|
||||||
|
{
|
||||||
|
foreach (T item in source)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (releaseElements)
|
||||||
|
ComRelease.Release(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComRelease.Release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension for a Com enumeration. Disposes the enumerated object and - optionally - the returned elements.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The object to be enumerated. This will be released.</param>
|
||||||
|
/// <param name="releaseElements">If true (the default), elements will also be released.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable ComEnum(this IEnumerable source, bool releaseElements = true)
|
||||||
|
{
|
||||||
|
foreach (object item in source)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (releaseElements)
|
||||||
|
ComRelease.Release(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ComRelease.Release(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper for enumeration that disposes the returned items. Note that source will not be disposed,
|
||||||
|
/// as that is normally done by foreach.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<T> DisposeEnum<T>(this IEnumerable<T> source)
|
||||||
|
where T : IDisposable
|
||||||
|
{
|
||||||
|
foreach (T item in source)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
item.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static void GarbageCollect()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Timers
|
||||||
|
|
||||||
|
public static void Delayed(LogContext log, int millis, System.Action action)
|
||||||
|
{
|
||||||
|
RegisterTimer(log, millis, action, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Timed(LogContext log, int millis, System.Action action)
|
||||||
|
{
|
||||||
|
RegisterTimer(log, millis, action, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterTimer(LogContext log, int millis, System.Action action, bool repeat)
|
||||||
|
{
|
||||||
|
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
|
||||||
|
timer.Interval = millis;
|
||||||
|
timer.Tick += (s, eargs) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
if (!repeat)
|
||||||
|
{
|
||||||
|
timer.Enabled = false;
|
||||||
|
timer.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(log, "Exception in timer: {0}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,9 +147,9 @@ namespace Acacia.ZPush.Connect
|
|||||||
// TODO: it would be nice to let the system handle the SecureString for the password. However,
|
// TODO: it would be nice to let the system handle the SecureString for the password. However,
|
||||||
// when specifying credentials for an HttpClient, they are only used after a 401 is received
|
// when specifying credentials for an HttpClient, they are only used after a 401 is received
|
||||||
// on the first request, basically doubling the number of requests.
|
// on the first request, basically doubling the number of requests.
|
||||||
using (SecureString pass = _account.Password)
|
using (SecureString pass = _account.Account.Password)
|
||||||
{
|
{
|
||||||
var byteArray = Encoding.UTF8.GetBytes(_account.UserName + ":" + pass.ConvertToUnsecureString());
|
var byteArray = Encoding.UTF8.GetBytes(_account.Account.UserName + ":" + pass.ConvertToUnsecureString());
|
||||||
var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
|
var header = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
|
||||||
_client.DefaultRequestHeaders.Authorization = header;
|
_client.DefaultRequestHeaders.Authorization = header;
|
||||||
}
|
}
|
||||||
@ -278,10 +278,10 @@ namespace Acacia.ZPush.Connect
|
|||||||
|
|
||||||
public Response Execute(ActiveSync.RequestBase request)
|
public Response Execute(ActiveSync.RequestBase request)
|
||||||
{
|
{
|
||||||
string url = string.Format(ACTIVESYNC_URL, _account.ServerURL, _account.DeviceId,
|
string url = string.Format(ACTIVESYNC_URL, _account.Account.ServerURL, _account.Account.DeviceId,
|
||||||
request.Command, _account.UserName, "WindowsOutlook");
|
request.Command, _account.Account.UserName, "WindowsOutlook");
|
||||||
|
|
||||||
// Parse the body
|
// Construct the body
|
||||||
WBXMLDocument doc = new WBXMLDocument();
|
WBXMLDocument doc = new WBXMLDocument();
|
||||||
doc.LoadXml(request.Body);
|
doc.LoadXml(request.Body);
|
||||||
doc.VersionNumber = 1.3;
|
doc.VersionNumber = 1.3;
|
||||||
@ -291,8 +291,11 @@ namespace Acacia.ZPush.Connect
|
|||||||
|
|
||||||
using (HttpContent content = new ByteArrayContent(contentBody))
|
using (HttpContent content = new ByteArrayContent(contentBody))
|
||||||
{
|
{
|
||||||
Logger.Instance.Trace(this, "Sending request: {0} -> {1}", _account.ServerURL, doc.ToXMLString());
|
Logger.Instance.Trace(this, "Sending request: {0} -> {1}", _account.Account.ServerURL, doc.ToXMLString());
|
||||||
content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-sync.wbxml");
|
content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-sync.wbxml");
|
||||||
|
string caps = ZPushCapabilities.Client.ToString();
|
||||||
|
Logger.Instance.Trace(this, "Sending request: {0} -> {1}: {2}", _account.Account.ServerURL, caps, doc.ToXMLString());
|
||||||
|
content.Headers.Add(Constants.ZPUSH_HEADER_CLIENT_CAPABILITIES, caps);
|
||||||
using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel).Result)
|
using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel).Result)
|
||||||
{
|
{
|
||||||
return new Response(response);
|
return new Response(response);
|
||||||
|
@ -46,14 +46,14 @@ namespace Acacia.ZPush.Connect
|
|||||||
public ResponseType Execute<ResponseType>(SoapRequest<ResponseType> request)
|
public ResponseType Execute<ResponseType>(SoapRequest<ResponseType> request)
|
||||||
{
|
{
|
||||||
// Create the url
|
// Create the url
|
||||||
string url = string.Format(ACTIVESYNC_URL, _connection.Account.ServerURL, "webservice",
|
string url = string.Format(ACTIVESYNC_URL, _connection.Account.Account.ServerURL, "webservice",
|
||||||
ServiceName,
|
ServiceName,
|
||||||
// TODO: this username is a bit of a quick hack.
|
// TODO: this username is a bit of a quick hack.
|
||||||
request.UserName ?? _connection.Account.UserName,
|
request.UserName ?? _connection.Account.Account.UserName,
|
||||||
"webservice");
|
"webservice");
|
||||||
|
|
||||||
// Set up the encoding
|
// Set up the encoding
|
||||||
SoapRequestEncoder encoder = new SoapRequestEncoder(_connection.Account.ServerURL, ServiceParameters, request);
|
SoapRequestEncoder encoder = new SoapRequestEncoder(_connection.Account.Account.ServerURL, ServiceParameters, request);
|
||||||
encoder.ServiceName = ServiceName;
|
encoder.ServiceName = ServiceName;
|
||||||
|
|
||||||
// Execute the request
|
// Execute the request
|
||||||
@ -85,7 +85,7 @@ namespace Acacia.ZPush.Connect
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
SoapParameters parameters = new SoapParameters();
|
SoapParameters parameters = new SoapParameters();
|
||||||
parameters.Add("devid", _connection.Account.DeviceId.ToLower());
|
parameters.Add("devid", _connection.Account.Account.DeviceId.ToLower());
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
using Acacia.Features;
|
using Acacia.Features;
|
||||||
using Acacia.Stubs;
|
using Acacia.Stubs;
|
||||||
using Microsoft.Office.Interop.Outlook;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user