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
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AcaciaZPushPlugin", "AcaciaZPushPlugin\AcaciaZPushPlugin.csproj", "{1A7427A5-F814-4B07-98B2-C67D758B65D6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginDebugger", "PluginDebugger\PluginDebugger.csproj", "{9258AD17-0A25-4669-A95C-93EC70882551}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OutlookRestarter", "OutlookRestarter\OutlookRestarter.csproj", "{222C4DA5-FA31-471A-B127-5E0C6AD2CB3C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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|x86.ActiveCfg = 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
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -125,7 +125,7 @@
|
||||
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
|
||||
<DefineConstants>VSTO40</DefineConstants>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<!--
|
||||
@ -241,6 +241,7 @@
|
||||
<Compile Include="Controls\KUITask.cs" />
|
||||
<Compile Include="Controls\KUIUtil.cs" />
|
||||
<Compile Include="DebugOptions.cs" />
|
||||
<Compile Include="Features\SecondaryContacts\FeatureSecondaryContacts.cs" />
|
||||
<Compile Include="Features\DebugSupport\AboutDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@ -275,13 +276,44 @@
|
||||
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
||||
<Compile Include="GlobalOptions.cs" />
|
||||
<Compile Include="Logging.cs" />
|
||||
<Compile Include="Native\MAPI.cs" />
|
||||
<Compile Include="Native\IOleWindow.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\RibbonToggleButton.cs" />
|
||||
<Compile Include="UI\Outlook\RibbonButton.cs" />
|
||||
<Compile Include="UI\Outlook\CommandElement.cs" />
|
||||
<Compile Include="UI\Outlook\MenuItem.cs" />
|
||||
<Compile Include="UI\Outlook\Types.cs" />
|
||||
<Compile Include="Utils\DisposableWrapper.cs" />
|
||||
<Compile Include="Utils\ImageUtils.cs" />
|
||||
<Compile Include="Utils\RegistryUtil.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\AvailableFolder.cs" />
|
||||
<Compile Include="ZPush\API\SharedFolders\SharedFolder.cs" />
|
||||
@ -306,8 +338,7 @@
|
||||
<Compile Include="ZPush\Connect\ZPushRequestEncoder.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapRequestEncoder.cs" />
|
||||
<Compile Include="ZPush\Connect\Soap\SoapRequest.cs" />
|
||||
<Compile Include="Stubs\ItemType.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\DisposableWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\ComWrapper.cs" />
|
||||
<Compile Include="UI\FeatureSettings.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
@ -393,7 +424,6 @@
|
||||
<Compile Include="Stubs\INoteItem.cs" />
|
||||
<Compile Include="Stubs\ISearch.cs" />
|
||||
<Compile Include="Stubs\IStorageItem.cs" />
|
||||
<Compile Include="Stubs\IUserProperty.cs" />
|
||||
<Compile Include="Stubs\IZPushItem.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\AddressBookWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\DistributionListWrapper.cs" />
|
||||
@ -408,7 +438,6 @@
|
||||
<Compile Include="Stubs\OutlookWrappers\SearchWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\StorageItemWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\StoreWrapper.cs" />
|
||||
<Compile Include="Stubs\OutlookWrappers\UserPropertyWrapper.cs" />
|
||||
<Compile Include="Stubs\IStore.cs" />
|
||||
<Compile Include="UI\ProgressDialog.cs">
|
||||
<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_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_VERSION = "X-Z-Push-Version";
|
||||
|
||||
|
@ -68,19 +68,25 @@ namespace Acacia
|
||||
}
|
||||
|
||||
public class EnumOption<EnumType> : Option<EnumType>
|
||||
where EnumType : struct
|
||||
{
|
||||
private readonly EnumType? _defaultValue;
|
||||
|
||||
private EnumType DefaultValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_defaultValue.HasValue)
|
||||
return (EnumType)_defaultValue;
|
||||
return (EnumType)typeof(EnumType).GetEnumValues().GetValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
public EnumOption(string token)
|
||||
public EnumOption(string token, EnumType? defaultValue = null)
|
||||
:
|
||||
base(token)
|
||||
{
|
||||
this._defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public override string GetToken(EnumType value)
|
||||
|
@ -47,6 +47,76 @@ namespace Acacia.Features.DebugSupport
|
||||
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
|
||||
|
||||
private const string INDENT = "+";
|
||||
@ -89,11 +159,12 @@ namespace Acacia.Features.DebugSupport
|
||||
|
||||
private void buttonGC_Click(object sender, EventArgs e)
|
||||
{
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
GarbageCollect();
|
||||
}
|
||||
|
||||
private void GarbageCollect()
|
||||
{
|
||||
Util.GarbageCollect();
|
||||
UpdateFields();
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
Version,
|
||||
Memory,
|
||||
Tasks,
|
||||
Wrappers,
|
||||
Misc,
|
||||
System,
|
||||
@ -101,9 +102,9 @@ namespace Acacia.Features.DebugSupport
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@ -133,6 +134,25 @@ namespace Acacia.Features.DebugSupport
|
||||
|
||||
#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
|
||||
|
||||
[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)]
|
||||
public bool ZPushSync
|
||||
{
|
||||
@ -227,14 +241,14 @@ namespace Acacia.Features.DebugSupport
|
||||
|
||||
#endregion
|
||||
|
||||
#region Outlook
|
||||
#region Outlook
|
||||
|
||||
[DebugCategory(DebugCategory.System)]
|
||||
public string OutlookVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisAddIn.Instance.Application.Version;
|
||||
return ThisAddIn.Instance.Version;
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +261,7 @@ namespace Acacia.Features.DebugSupport
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
|
@ -13,8 +13,6 @@
|
||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Acacia.Features.ReplyFlags;
|
||||
@ -47,8 +45,16 @@ namespace Acacia.Features.DebugSupport
|
||||
RegisterButton(this, "Settings", false, ShowSettings);
|
||||
}
|
||||
|
||||
|
||||
public override void AfterStartup()
|
||||
{
|
||||
/*DebugDialog dd = new DebugDialog();
|
||||
dd.Show();
|
||||
dd.DebugCycle(5);*/
|
||||
}
|
||||
|
||||
#region About dialog
|
||||
|
||||
|
||||
public void ShowAbout()
|
||||
{
|
||||
new AboutDialog().ShowDialog();
|
||||
|
@ -25,6 +25,9 @@ namespace Acacia.Features.DebugSupport
|
||||
{
|
||||
public static class Statistics
|
||||
{
|
||||
public static long StartedTasks;
|
||||
public static long FinishedTasks;
|
||||
|
||||
public static long CreatedWrappers;
|
||||
public static long DeletedWrappers;
|
||||
public static long DisposedWrappers;
|
||||
|
@ -14,7 +14,6 @@
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -58,9 +57,9 @@ namespace Acacia.Features
|
||||
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
|
||||
@ -195,14 +194,11 @@ namespace Acacia.Features
|
||||
|
||||
#region Event helpers
|
||||
|
||||
private static MailEvents _mailEvents;
|
||||
protected static MailEvents MailEvents
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mailEvents == null)
|
||||
_mailEvents = new MailEvents(App);
|
||||
return _mailEvents;
|
||||
return ThisAddIn.Instance.MailEvents;
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,6 +223,11 @@ namespace Acacia.Features
|
||||
|
||||
}
|
||||
|
||||
public virtual void AfterStartup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Z-Push channels
|
||||
|
@ -33,6 +33,7 @@ namespace Acacia.Features
|
||||
typeof(FreeBusy.FeatureFreeBusy),
|
||||
typeof(GAB.FeatureGAB),
|
||||
typeof(Notes.FeatureNotes),
|
||||
typeof(SecondaryContacts.FeatureSecondaryContacts),
|
||||
typeof(SendAs.FeatureSendAs),
|
||||
typeof(DebugSupport.FeatureDebugSupport)
|
||||
};
|
||||
|
@ -103,7 +103,7 @@ namespace Acacia.Features.FreeBusy
|
||||
|
||||
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,12 +190,14 @@ namespace Acacia.Features.FreeBusy
|
||||
if (account != null && handler.Contacts != null)
|
||||
{
|
||||
// Look for the email address. If found, use the account associated with the GAB
|
||||
ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>();
|
||||
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
|
||||
using (IItem result = search.SearchOne())
|
||||
using (ISearch<IContactItem> search = handler.Contacts.Search<IContactItem>())
|
||||
{
|
||||
if (result != null)
|
||||
return account;
|
||||
search.AddField("urn:schemas:contacts:email1").SetOperation(SearchOperation.Equal, username);
|
||||
using (IItem result = search.SearchOne())
|
||||
{
|
||||
if (result != null)
|
||||
return account;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -39,7 +38,7 @@ namespace Acacia.Features.GAB
|
||||
private readonly Dictionary<string, GABHandler> _gabsByDomainName = new Dictionary<string, GABHandler>();
|
||||
private readonly HashSet<string> _gabFolders = new HashSet<string>();
|
||||
private readonly HashSet<string> _domains = new HashSet<string>();
|
||||
private ZPushLocalStore _store;
|
||||
private IStore _store;
|
||||
private int _processing;
|
||||
|
||||
public FeatureGAB()
|
||||
@ -64,8 +63,11 @@ namespace Acacia.Features.GAB
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
MailEvents.BeforeDelete += SuppressEventHandler_Delete;
|
||||
MailEvents.Write += SuppressEventHandler_Modify;
|
||||
if (SuppressModifications && MailEvents != null)
|
||||
{
|
||||
MailEvents.BeforeDelete += SuppressEventHandler_Delete;
|
||||
MailEvents.Write += SuppressEventHandler_Modify;
|
||||
}
|
||||
Watcher.AccountDiscovered += AccountDiscovered;
|
||||
Watcher.AccountRemoved += AccountRemoved;
|
||||
Watcher.AccountsScanned += AccountsScanned;
|
||||
@ -118,6 +120,15 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
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. " +
|
||||
"This should only be disabled for debug purposes.")]
|
||||
public bool CreateContacts
|
||||
@ -173,6 +184,42 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
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
|
||||
|
||||
#region Modification suppression
|
||||
@ -203,7 +250,7 @@ namespace Acacia.Features.GAB
|
||||
if (_processing == 0)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
@ -233,16 +280,19 @@ namespace Acacia.Features.GAB
|
||||
/// <param name="cancel"></param>
|
||||
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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Show message and cancel event
|
||||
MessageBox.Show(StringUtil.GetResourceString("GABEvent_Body"),
|
||||
StringUtil.GetResourceString("GABEvent_Title"),
|
||||
MessageBoxButtons.OK,
|
||||
@ -263,16 +313,15 @@ namespace Acacia.Features.GAB
|
||||
BeginProcessing();
|
||||
|
||||
// Delete any contacts folders in the local store
|
||||
using (ZPushLocalStore store = ZPushLocalStore.GetInstance(App))
|
||||
if (DeleteExistingFolder)
|
||||
{
|
||||
if (store != null)
|
||||
using (IStore store = ZPushLocalStore.GetInstance(ThisAddIn.Instance))
|
||||
{
|
||||
using (IFolder root = store.RootFolder)
|
||||
if (store != null)
|
||||
{
|
||||
foreach (IFolder folder in root.GetSubFolders<IFolder>())
|
||||
using (IFolder root = store.GetRootFolder())
|
||||
{
|
||||
// TODO: let enumerator handle this
|
||||
using (folder)
|
||||
foreach (IFolder folder in root.GetSubFolders<IFolder>().DisposeEnum())
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -293,10 +342,14 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
|
||||
// Do the resync
|
||||
int remaining = _gabsByDomainName.Count;
|
||||
foreach (GABHandler gab in _gabsByDomainName.Values)
|
||||
{
|
||||
Logger.Instance.Debug(this, "FullResync: Starting resync: {0}", gab.DisplayName);
|
||||
Tasks.Task(this, "FullResync", () => gab.FullResync());
|
||||
Tasks.Task(this, "FullResync", () =>
|
||||
{
|
||||
gab.FullResync();
|
||||
});
|
||||
}
|
||||
}
|
||||
finally
|
||||
@ -353,12 +406,12 @@ namespace Acacia.Features.GAB
|
||||
_store.Dispose();
|
||||
_store = null;
|
||||
}
|
||||
_store = ZPushLocalStore.GetInstance(App);
|
||||
_store = ZPushLocalStore.GetInstance(ThisAddIn.Instance);
|
||||
if (_store == null)
|
||||
return null;
|
||||
|
||||
// Try to find the existing GAB
|
||||
using (IFolder root = _store.RootFolder)
|
||||
using (IFolder root = _store.GetRootFolder())
|
||||
{
|
||||
IAddressBook gab = FindGABForDomain(root, domainName);
|
||||
if (gab == null)
|
||||
@ -376,13 +429,16 @@ namespace Acacia.Features.GAB
|
||||
gab.AttrHidden = false;
|
||||
|
||||
// Update admin
|
||||
_gabFolders.Add(gab.EntryId);
|
||||
_gabFolders.Add(gab.EntryID);
|
||||
GABInfo gabInfo = GABInfo.Get(gab, domainName);
|
||||
gabInfo.Store(gab);
|
||||
|
||||
// Hook BeforeMove event to prevent modifications
|
||||
// TODO: use ZPushWatcher for this?
|
||||
gab.BeforeItemMove += SuppressMoveEventHandler;
|
||||
if (SuppressModifications)
|
||||
{
|
||||
// Hook BeforeMove event to prevent modifications
|
||||
// TODO: use ZPushWatcher for this?
|
||||
gab.BeforeItemMove += SuppressMoveEventHandler;
|
||||
}
|
||||
|
||||
return gab;
|
||||
}
|
||||
@ -390,8 +446,11 @@ namespace Acacia.Features.GAB
|
||||
|
||||
private void DisposeGABContacts(IAddressBook gab)
|
||||
{
|
||||
// Unhook the event to prevent the gab lingering in memory
|
||||
gab.BeforeItemMove -= SuppressMoveEventHandler;
|
||||
if (SuppressModifications)
|
||||
{
|
||||
// Unhook the event to prevent the gab lingering in memory
|
||||
gab.BeforeItemMove -= SuppressMoveEventHandler;
|
||||
}
|
||||
}
|
||||
|
||||
public static GABInfo GetGABContactsFolderInfo(IFolder folder)
|
||||
@ -410,7 +469,7 @@ namespace Acacia.Features.GAB
|
||||
private void AccountDiscovered(ZPushAccount zpush)
|
||||
{
|
||||
Logger.Instance.Info(this, "Account discovered: {0}", zpush.DisplayName);
|
||||
_domains.Add(zpush.DomainName);
|
||||
_domains.Add(zpush.Account.DomainName);
|
||||
|
||||
zpush.ConfirmedChanged += (z) =>
|
||||
{
|
||||
@ -469,12 +528,12 @@ namespace Acacia.Features.GAB
|
||||
_store.Dispose();
|
||||
_store = null;
|
||||
}
|
||||
_store = ZPushLocalStore.GetInstance(App);
|
||||
_store = ZPushLocalStore.GetInstance(ThisAddIn.Instance);
|
||||
if (_store == null)
|
||||
return;
|
||||
|
||||
bool deletedSomething = false;
|
||||
using (IFolder root = _store.RootFolder)
|
||||
using (IFolder root = _store.GetRootFolder())
|
||||
{
|
||||
foreach (IFolder subfolder in root.GetSubFolders<IFolder>())
|
||||
{
|
||||
@ -484,7 +543,7 @@ namespace Acacia.Features.GAB
|
||||
GABInfo info = GetGABContactsFolderInfo(subfolder);
|
||||
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
|
||||
{
|
||||
deletedSomething = true;
|
||||
@ -500,7 +559,7 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
|
||||
if (deletedSomething)
|
||||
EmptyDeletedItems();
|
||||
DoEmptyDeletedItems();
|
||||
}
|
||||
|
||||
private void CheckGABRemoved()
|
||||
@ -535,14 +594,14 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
}
|
||||
|
||||
EmptyDeletedItems();
|
||||
DoEmptyDeletedItems();
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterGABAccount(ZPushAccount account, IFolder folder)
|
||||
{
|
||||
// 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
|
||||
GABHandler gab;
|
||||
@ -573,7 +632,7 @@ namespace Acacia.Features.GAB
|
||||
|
||||
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);
|
||||
|
||||
@ -606,7 +665,7 @@ namespace Acacia.Features.GAB
|
||||
try
|
||||
{
|
||||
gab.Process(item);
|
||||
EmptyDeletedItems();
|
||||
DoEmptyDeletedItems();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -615,8 +674,11 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
}
|
||||
|
||||
private void EmptyDeletedItems()
|
||||
private void DoEmptyDeletedItems()
|
||||
{
|
||||
if (!EmptyDeletedItems)
|
||||
return;
|
||||
|
||||
if (_store != null)
|
||||
_store.EmptyDeletedItems();
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
get
|
||||
{
|
||||
using(IStore store = Folder.Store)
|
||||
using(IStore store = Folder.GetStore())
|
||||
return store.DisplayName;
|
||||
}
|
||||
}
|
||||
@ -136,6 +136,13 @@ namespace Acacia.Features.GAB
|
||||
|
||||
private void ClearContacts()
|
||||
{
|
||||
if (!_feature.ClearContacts)
|
||||
{
|
||||
using (IStorageItem item = GetIndexItem())
|
||||
item?.Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Contacts != null)
|
||||
{
|
||||
try
|
||||
@ -193,24 +200,21 @@ namespace Acacia.Features.GAB
|
||||
return;
|
||||
|
||||
// Process the messages
|
||||
foreach (IItem item in Folder.Items)
|
||||
foreach (IZPushItem item in Folder.Items.Typed<IZPushItem>())
|
||||
{
|
||||
// TODO: make type-checking iterator?
|
||||
if (item is IZPushItem)
|
||||
// Store the entry id to fetch again later, the item will be disposed
|
||||
string entryId = item.EntryID;
|
||||
Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject);
|
||||
if (_feature.ProcessItems2)
|
||||
{
|
||||
string entryId = item.EntryId;
|
||||
Logger.Instance.Trace(this, "Checking chunk: {0}", item.Subject);
|
||||
if (_feature.ProcessItems2)
|
||||
Tasks.Task(_feature, "ProcessChunk", () =>
|
||||
{
|
||||
Tasks.Task(_feature, "ProcessChunk", () =>
|
||||
using (IItem item2 = Folder.GetItemById(entryId))
|
||||
{
|
||||
using (IItem item2 = Folder.GetItemById(entryId))
|
||||
{
|
||||
if (item2 != null)
|
||||
ProcessMessage((IZPushItem)item2);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (item2 != null)
|
||||
ProcessMessage((IZPushItem)item2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,17 +265,18 @@ namespace Acacia.Features.GAB
|
||||
_feature?.BeginProcessing();
|
||||
try
|
||||
{
|
||||
// Delete the old contacts from this chunk
|
||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
||||
search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks);
|
||||
search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk);
|
||||
foreach (IItem oldItem in search.Search())
|
||||
if (_feature.ProcessMessageDeleteExisting)
|
||||
{
|
||||
// TODO: Search should handle this, like folder enumeration
|
||||
using (oldItem)
|
||||
// Delete the old contacts from this chunk
|
||||
using (ISearch<IItem> search = Contacts.Search<IItem>())
|
||||
{
|
||||
Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject);
|
||||
oldItem.Delete();
|
||||
search.AddField(PROP_SEQUENCE, true).SetOperation(SearchOperation.Equal, index.numberOfChunks);
|
||||
search.AddField(PROP_CHUNK, true).SetOperation(SearchOperation.Equal, index.chunk);
|
||||
foreach (IItem oldItem in search.Search())
|
||||
{
|
||||
Logger.Instance.Trace(this, "Deleting GAB entry: {0}", oldItem.Subject);
|
||||
oldItem.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,7 +302,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
return index?.GetUserProperty<int>(PROP_CURRENT_SEQUENCE)?.Value;
|
||||
return index?.GetUserProperty<int?>(PROP_CURRENT_SEQUENCE);
|
||||
}
|
||||
}
|
||||
set
|
||||
@ -306,7 +311,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = value.Value;
|
||||
index.SetUserProperty<int>(PROP_CURRENT_SEQUENCE, value.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -316,22 +321,25 @@ namespace Acacia.Features.GAB
|
||||
}
|
||||
}
|
||||
|
||||
private IItem FindNewestChunk()
|
||||
private ChunkIndex? FindNewestChunkIndex()
|
||||
{
|
||||
if (Folder == null)
|
||||
return null;
|
||||
|
||||
// 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;
|
||||
foreach(IItem item in Folder.ItemsSorted("LastModificationTime", true))
|
||||
foreach(IItem item in Folder.Items.Sort("LastModificationTime", true))
|
||||
{
|
||||
if (ChunkIndex.Parse(item.Subject) != null)
|
||||
return item;
|
||||
item.Dispose();
|
||||
if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK)
|
||||
return null;
|
||||
++i;
|
||||
using (item)
|
||||
{
|
||||
ChunkIndex? index = ChunkIndex.Parse(item.Subject);
|
||||
if (index != null)
|
||||
return index;
|
||||
if (i > Constants.ZPUSH_GAB_NEWEST_MAX_CHECK)
|
||||
return null;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -341,39 +349,39 @@ namespace Acacia.Features.GAB
|
||||
try
|
||||
{
|
||||
// Find the newest chunk
|
||||
using (IItem newest = FindNewestChunk())
|
||||
ChunkIndex? newestChunkIndex = FindNewestChunkIndex();
|
||||
if (newestChunkIndex == null)
|
||||
{
|
||||
if (newest == null)
|
||||
CurrentSequence = null;
|
||||
else
|
||||
CurrentSequence = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Trace(this, "Newest chunk: {0}", newestChunkIndex.Value);
|
||||
|
||||
int? currentSequence = CurrentSequence;
|
||||
if (!currentSequence.HasValue || currentSequence.Value != newestChunkIndex?.numberOfChunks)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Newest chunk: {0}", newest.Subject);
|
||||
ChunkIndex? newestChunkIndex = ChunkIndex.Parse(newest.Subject);
|
||||
// Sequence has changed. Delete contacts
|
||||
Logger.Instance.Trace(this, "Rechunked, deleting contacts");
|
||||
ClearContacts();
|
||||
|
||||
if (!CurrentSequence.HasValue || CurrentSequence.Value != newestChunkIndex?.numberOfChunks)
|
||||
// Determine new sequence
|
||||
if (newestChunkIndex == null)
|
||||
{
|
||||
// Sequence has changed. Delete contacts
|
||||
Logger.Instance.Trace(this, "Rechunked, deleting contacts");
|
||||
ClearContacts();
|
||||
|
||||
// Determine new sequence
|
||||
if (newestChunkIndex == null)
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
if (index != null)
|
||||
index.Delete();
|
||||
}
|
||||
if (index != null)
|
||||
index.Delete();
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
int numberOfChunks = newestChunkIndex.Value.numberOfChunks;
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
int numberOfChunks = newestChunkIndex.Value.numberOfChunks;
|
||||
using (IStorageItem index = GetIndexItem())
|
||||
{
|
||||
index.GetUserProperty<int>(PROP_CURRENT_SEQUENCE, true).Value = numberOfChunks;
|
||||
index.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = CreateChunkStateString(numberOfChunks);
|
||||
index.Save();
|
||||
}
|
||||
index.SetUserProperty(PROP_CURRENT_SEQUENCE, numberOfChunks);
|
||||
index.SetUserProperty(PROP_LAST_PROCESSED, CreateChunkStateString(numberOfChunks));
|
||||
index.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -402,7 +410,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
if (item == null)
|
||||
return null;
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED);
|
||||
if (string.IsNullOrEmpty(state))
|
||||
return null;
|
||||
|
||||
@ -420,7 +428,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
using (IStorageItem item = GetIndexItem())
|
||||
{
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED)?.Value;
|
||||
string state = item.GetUserProperty<string>(PROP_LAST_PROCESSED);
|
||||
string[] parts;
|
||||
if (string.IsNullOrEmpty(state))
|
||||
parts = new string[index.numberOfChunks];
|
||||
@ -434,7 +442,7 @@ namespace Acacia.Features.GAB
|
||||
parts[index.chunk] = partState;
|
||||
string combined = string.Join(";", parts);
|
||||
|
||||
item.GetUserProperty<string>(PROP_LAST_PROCESSED, true).Value = combined;
|
||||
item.SetUserProperty(PROP_LAST_PROCESSED, combined);
|
||||
item.Save();
|
||||
}
|
||||
}
|
||||
@ -598,7 +606,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
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)
|
||||
AddGroupMember(group, item);
|
||||
}
|
||||
@ -613,17 +621,19 @@ namespace Acacia.Features.GAB
|
||||
|
||||
private IItem FindItemById(string id)
|
||||
{
|
||||
ISearch<IItem> search = Contacts.Search<IItem>();
|
||||
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
|
||||
return search.SearchOne();
|
||||
using (ISearch<IItem> search = Contacts.Search<IItem>())
|
||||
{
|
||||
search.AddField(PROP_GAB_ID, true).SetOperation(SearchOperation.Equal, id);
|
||||
return search.SearchOne();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemStandard(IItem item, string id, Dictionary<string, object> value, ChunkIndex index)
|
||||
{
|
||||
// Set the chunk data
|
||||
item.GetUserProperty<int>(PROP_SEQUENCE, true).Value = index.numberOfChunks;
|
||||
item.GetUserProperty<int>(PROP_CHUNK, true).Value = index.chunk;
|
||||
item.GetUserProperty<string>(PROP_GAB_ID, true).Value = id;
|
||||
item.SetUserProperty(PROP_SEQUENCE, index.numberOfChunks);
|
||||
item.SetUserProperty(PROP_CHUNK, index.chunk);
|
||||
item.SetUserProperty(PROP_GAB_ID, id);
|
||||
}
|
||||
|
||||
private void AddGroupMember(IDistributionList group, IItem item)
|
||||
@ -653,7 +663,7 @@ namespace Acacia.Features.GAB
|
||||
{
|
||||
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)
|
||||
{
|
||||
AddGroupMember((IDistributionList)groupItem, item);
|
||||
|
@ -18,7 +18,6 @@ using Acacia.Stubs;
|
||||
using Acacia.Stubs.OutlookWrappers;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
@ -84,7 +83,7 @@ namespace Acacia.Features.Notes
|
||||
PatchIfConfirmed(folder);
|
||||
}
|
||||
|
||||
private bool IsNotesFolder(OutlookConstants.SyncType type)
|
||||
private bool IsNotesFolder(OutlookConstants.SyncType? type)
|
||||
{
|
||||
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
|
||||
// issues with the folder object being disposed in the past
|
||||
string folderId = folder.EntryId;
|
||||
string folderId = folder.EntryID;
|
||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(folder);
|
||||
if (zpush != null)
|
||||
{
|
||||
@ -122,13 +121,13 @@ namespace Acacia.Features.Notes
|
||||
Logger.Instance.Trace(this, "PatchFolder: {0}", folderId);
|
||||
try
|
||||
{
|
||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
||||
using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId))
|
||||
{
|
||||
if (folder == null)
|
||||
return;
|
||||
|
||||
// Patch if needed
|
||||
OutlookConstants.SyncType type = FolderUtils.GetFolderSyncType(folder);
|
||||
OutlookConstants.SyncType? type = FolderUtils.GetFolderSyncType(folder);
|
||||
Logger.Instance.Trace(this, "Notes folder type: {0}", type);
|
||||
if (IsNotesFolder(type))
|
||||
{
|
||||
@ -168,13 +167,13 @@ namespace Acacia.Features.Notes
|
||||
Logger.Instance.Trace(this, "UnpatchFolder: {0}", folderId);
|
||||
try
|
||||
{
|
||||
using (IFolder folder = Mapping.GetFolderFromID(folderId))
|
||||
using (IFolder folder = ThisAddIn.Instance.GetFolderFromID(folderId))
|
||||
{
|
||||
if (folder == null)
|
||||
return;
|
||||
|
||||
// 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);
|
||||
// Unpatch only if the original type is a notes folder, but the current type isn't
|
||||
if (IsNotesFolder(type) && !IsNotesFolder(FolderUtils.GetFolderSyncType(folder)))
|
||||
@ -220,7 +219,7 @@ namespace Acacia.Features.Notes
|
||||
{
|
||||
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
|
||||
item.SetProperties(
|
||||
|
@ -19,7 +19,6 @@ using Acacia.UI.Outlook;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Acacia.ZPush.Connect;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -48,6 +47,12 @@ namespace Acacia.Features.OutOfOffice
|
||||
Watcher.ZPushAccountChange += Watcher_ZPushAccountChange;
|
||||
}
|
||||
|
||||
override public void GetCapabilities(ZPushCapabilities caps)
|
||||
{
|
||||
caps.Add("oof");
|
||||
caps.Add("ooftime");
|
||||
}
|
||||
|
||||
private static bool IsOOFEnabled(ActiveSync.SettingsOOF settings)
|
||||
{
|
||||
if (settings == null)
|
||||
@ -227,7 +232,7 @@ namespace Acacia.Features.OutOfOffice
|
||||
if (oof.State != ActiveSync.OOFState.Disabled)
|
||||
{
|
||||
if (MessageBox.Show(
|
||||
string.Format(Properties.Resources.OOFStartup_Message, account.SmtpAddress),
|
||||
string.Format(Properties.Resources.OOFStartup_Message, account.Account.SmtpAddress),
|
||||
Properties.Resources.OOFStartup_Title,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
|
@ -43,7 +43,7 @@ namespace Acacia.Features.OutOfOffice
|
||||
InitializeComponent();
|
||||
|
||||
// Add the email address to the title
|
||||
Text = string.Format(Text, account.SmtpAddress);
|
||||
Text = string.Format(Text, account.Account.SmtpAddress);
|
||||
|
||||
// Set the time formats
|
||||
timeFrom.CustomFormat = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
|
||||
|
@ -22,7 +22,6 @@ using System.Threading.Tasks;
|
||||
using Acacia.Stubs;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using static Acacia.DebugOptions;
|
||||
|
||||
namespace Acacia.Features.ReplyFlags
|
||||
@ -48,18 +47,30 @@ namespace Acacia.Features.ReplyFlags
|
||||
if (ReadEvent)
|
||||
{
|
||||
// As a fallback, add an event handler to update the message when displaying it
|
||||
MailEvents.Read += UpdateReplyStatus;
|
||||
if (MailEvents != null)
|
||||
{
|
||||
MailEvents.Read += UpdateReplyStatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (SendEvents)
|
||||
{
|
||||
// Hook reply and send events to update local state to server
|
||||
MailEvents.Reply += OnReply;
|
||||
MailEvents.ReplyAll += OnReplyAll;
|
||||
MailEvents.Forward += OnForwarded;
|
||||
if (MailEvents != null)
|
||||
{
|
||||
MailEvents.Reply += OnReply;
|
||||
MailEvents.ReplyAll += OnReplyAll;
|
||||
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 " +
|
||||
"updated, it is checked to see if the reply flags are up to date. This is the main " +
|
||||
"mechanism for updating reply flags that change on the server")]
|
||||
|
@ -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.Utils;
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Features.SharedFolders;
|
||||
using Acacia.ZPush.API.SharedFolders;
|
||||
using static Acacia.DebugOptions;
|
||||
@ -30,7 +29,7 @@ using static Acacia.DebugOptions;
|
||||
namespace Acacia.Features.SendAs
|
||||
{
|
||||
[AcaciaOption("Provides the ability to select different senders for Z-Push accounts.")]
|
||||
public class FeatureSendAs : FeatureDisabled
|
||||
public class FeatureSendAs : Feature
|
||||
{
|
||||
private FeatureSharedFolders _sharedFolders;
|
||||
|
||||
@ -50,7 +49,10 @@ namespace Acacia.Features.SendAs
|
||||
|
||||
public override void Startup()
|
||||
{
|
||||
MailEvents.ItemSend += MailEvents_ItemSend;
|
||||
if (MailEvents != null)
|
||||
{
|
||||
MailEvents.ItemSend += MailEvents_ItemSend;
|
||||
}
|
||||
|
||||
if (SendAsOwner)
|
||||
{
|
||||
@ -58,7 +60,10 @@ namespace Acacia.Features.SendAs
|
||||
_sharedFolders = ThisAddIn.Instance.GetFeature<FeatureSharedFolders>();
|
||||
if (_sharedFolders != null)
|
||||
{
|
||||
MailEvents.Respond += MailEvents_Respond;
|
||||
if (MailEvents != null)
|
||||
{
|
||||
MailEvents.Respond += MailEvents_Respond;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,7 +71,7 @@ namespace Acacia.Features.SendAs
|
||||
private void MailEvents_Respond(IMailItem mail, IMailItem response)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Responding to mail, checking");
|
||||
using (IStore store = mail.Store)
|
||||
using (IStore store = mail.GetStore())
|
||||
{
|
||||
ZPushAccount zpush = Watcher.Accounts.GetAccount(store);
|
||||
Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush);
|
||||
@ -85,17 +90,21 @@ namespace Acacia.Features.SendAs
|
||||
{
|
||||
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
|
||||
// TODO: make a wrapper for this
|
||||
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())
|
||||
using (IRecipient recip = ThisAddIn.Instance.ResolveRecipient(shared.Store.UserName))
|
||||
{
|
||||
Logger.Instance.Trace(this, "Sending as: {0}", recip.AddressEntry.Address);
|
||||
response.SetSender(recip.AddressEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Trace(this, "Unable to resolve sender");
|
||||
Logger.Instance.Trace(this, "Checking, Shared folder owner recipient: {0}", recip.Name);
|
||||
if (recip != null && recip.IsResolved)
|
||||
{
|
||||
Logger.Instance.Trace(this, "Sending as: {0}", recip.Address);
|
||||
using (IAddressEntry address = recip.GetAddressEntry())
|
||||
{
|
||||
response.SetSender(address);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Instance.Trace(this, "Unable to resolve sender");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,13 +114,13 @@ namespace Acacia.Features.SendAs
|
||||
|
||||
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);
|
||||
if (zpush != null)
|
||||
{
|
||||
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);
|
||||
item.SetProperty(Constants.ZPUSH_SEND_AS, address);
|
||||
|
@ -71,7 +71,7 @@ namespace Acacia.Features.SharedFolders
|
||||
).Images;
|
||||
|
||||
// Add the email address to the title
|
||||
Text = string.Format(Text, account.SmtpAddress);
|
||||
Text = string.Format(Text, account.Account.SmtpAddress);
|
||||
|
||||
// Set up options
|
||||
ShowOptions(new KTreeNode[0]);
|
||||
@ -191,7 +191,7 @@ namespace Acacia.Features.SharedFolders
|
||||
ctx.AddBusy(-count);
|
||||
|
||||
// Sync account
|
||||
_account.SendReceive();
|
||||
_account.Account.SendReceive();
|
||||
|
||||
// Show 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
|
||||
/// 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/>.
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Acacia.UI;
|
||||
using Acacia.UI.Outlook;
|
||||
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()
|
||||
{
|
||||
ZPushAccount account = Watcher.CurrentZPushAccount();
|
||||
@ -107,15 +100,15 @@ namespace Acacia.Features.WebApp
|
||||
// Perform a cached auto discover
|
||||
try
|
||||
{
|
||||
Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.DomainName);
|
||||
Logger.Instance.Debug(this, "Starting kdiscover: {0}", account.Account.DomainName);
|
||||
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));
|
||||
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);
|
||||
return null;
|
||||
}
|
||||
@ -124,7 +117,7 @@ namespace Acacia.Features.WebApp
|
||||
private string PerformAutoDiscover(ZPushAccount account)
|
||||
{
|
||||
// Fetch the txt record
|
||||
IList<string> txt = DnsUtil.GetTxtRecord(account.DomainName);
|
||||
IList<string> txt = DnsUtil.GetTxtRecord(account.Account.DomainName);
|
||||
if (txt == null)
|
||||
return null;
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace Acacia
|
||||
get { return GetOption(null, THREADING); }
|
||||
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 " +
|
||||
"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
|
||||
|
||||
[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_CONTAINER_CLASS = PROP + "3613" + PT_UNICODE;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Email specific
|
||||
@ -120,6 +122,7 @@ namespace Acacia
|
||||
public const string PR_EAS_SYNCTYPE = PROP + "6A1A" + PT_LONG;
|
||||
public const string PR_EAS_SYNC2 = PROP + "6A1D" + PT_BOOLEAN;
|
||||
public const string PR_NET_FOLDER_FLAGS = PROP + "36DE" + PT_LONG;
|
||||
public const string PR_EAS_NAME = PROP + "6915" + PT_UNICODE;
|
||||
|
||||
public enum SyncType
|
||||
{
|
||||
|
@ -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>
|
||||
/// Looks up a localized string similar to Support.
|
||||
/// </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>
|
||||
/// Looks up a localized string similar to Unable to open the shared folder. Please ensure you have permission to open the shared folder..
|
||||
/// </summary>
|
||||
|
@ -431,4 +431,18 @@
|
||||
<data name="Ribbon_About_Supertip" xml:space="preserve">
|
||||
<value>Shows the about dialog, which contains licensing and version information.</value>
|
||||
</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>
|
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>
|
||||
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
|
||||
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||
@ -22,17 +22,7 @@ using System.Threading.Tasks;
|
||||
|
||||
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
|
||||
{
|
||||
public interface IBase : IDisposable
|
||||
public interface IBase : IComWrapper
|
||||
{
|
||||
#region MAPI properties
|
||||
#region Properties
|
||||
|
||||
bool AttrHidden { get; set; }
|
||||
|
||||
@ -34,23 +34,35 @@ namespace Acacia.Stubs
|
||||
|
||||
#endregion
|
||||
|
||||
string EntryId { get; }
|
||||
IFolder Parent { get; }
|
||||
string ParentEntryId { get; }
|
||||
#region Ids and hierarchy
|
||||
|
||||
string EntryID { get; }
|
||||
IFolder Parent { get; }
|
||||
string ParentEntryID { get; }
|
||||
|
||||
IStore Store { get; }
|
||||
/// <summary>
|
||||
/// Quick accessor to Store.Id, to prevent allocation a wrapper for it.
|
||||
/// Returns the store. The owner is responsible for disposing.
|
||||
/// </summary>
|
||||
string StoreId { get; }
|
||||
IStore GetStore();
|
||||
|
||||
/// <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>
|
||||
string StoreDisplayName { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
void Delete();
|
||||
|
||||
bool MustRelease { get; set; }
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
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; }
|
||||
|
||||
IEnumerable<IItem> Items { get; }
|
||||
|
||||
IEnumerable<IItem> ItemsSorted(string field, bool descending);
|
||||
IItems Items { get; }
|
||||
|
||||
IItem GetItemById(string id);
|
||||
|
||||
string FullFolderPath { get; }
|
||||
|
||||
ItemType DefaultItemType { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Searching
|
||||
@ -55,6 +57,11 @@ namespace Acacia.Stubs
|
||||
IEnumerable<FolderType> GetSubFolders<FolderType>()
|
||||
where FolderType : IFolder;
|
||||
|
||||
IFolders SubFolders
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
FolderType GetSubFolder<FolderType>(string name)
|
||||
where FolderType : IFolder;
|
||||
|
||||
@ -101,5 +108,11 @@ namespace Acacia.Stubs
|
||||
/// function prevents creating lots of wrappers.
|
||||
/// </summary>
|
||||
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 Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the events for the item. The caller is responsible for disposing.
|
||||
/// </summary>
|
||||
IItemEvents GetEvents();
|
||||
|
||||
#endregion
|
||||
|
||||
#region User properties
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the user property with the specified name.
|
||||
/// Retrieves the item's user property with the specified name.
|
||||
/// </summary>
|
||||
/// <param name="create">If true, the property is created if it does not exist.
|
||||
/// If false, null is returned in this case</param>
|
||||
IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false);
|
||||
/// <typeparam name="Type">The property type.</typeparam>
|
||||
/// <param name="name">The name of the property.</param>
|
||||
/// <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
|
||||
|
||||
|
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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.Stubs
|
||||
{
|
||||
@ -34,6 +33,10 @@ namespace Acacia.Stubs
|
||||
string SenderEmailAddress { 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
|
||||
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||
@ -22,17 +22,7 @@ using System.Threading.Tasks;
|
||||
|
||||
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
|
||||
{
|
||||
public enum SearchOperation
|
||||
/// <summary>
|
||||
/// Order matches MAPI RELOP_ constants
|
||||
/// </summary>
|
||||
public enum SearchOperation : uint
|
||||
{
|
||||
Smaller,
|
||||
SmallerEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Equal,
|
||||
NotEqual,
|
||||
SmallerEqual,
|
||||
Smaller,
|
||||
GreaterEqual,
|
||||
Greater,
|
||||
Like
|
||||
}
|
||||
|
||||
@ -41,7 +44,8 @@ namespace Acacia.Stubs
|
||||
public enum SearchOperator
|
||||
{
|
||||
Or,
|
||||
And
|
||||
And,
|
||||
Not
|
||||
}
|
||||
|
||||
public interface ISearchOperator
|
||||
@ -49,8 +53,7 @@ namespace Acacia.Stubs
|
||||
ISearchField AddField(string name, bool isUserField = false);
|
||||
}
|
||||
|
||||
public interface ISearch<ItemType>
|
||||
: ISearchOperator
|
||||
public interface ISearch<ItemType> : ISearchOperator, IDisposable
|
||||
where ItemType : IItem
|
||||
{
|
||||
ISearchOperator AddOperator(SearchOperator oper);
|
||||
|
@ -24,9 +24,29 @@ namespace Acacia.Stubs
|
||||
{
|
||||
public interface IStore : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the root folder.
|
||||
/// </summary>
|
||||
/// <returns>The root folder. The caller is responsible for disposing.</returns>
|
||||
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);
|
||||
string DisplayName { 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
|
||||
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
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 AddressBookWrapper : FolderWrapper, IAddressBook
|
||||
{
|
||||
public AddressBookWrapper(Folder folder)
|
||||
public AddressBookWrapper(NSOutlook.MAPIFolder folder)
|
||||
:
|
||||
base(folder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override IFolder Clone()
|
||||
{
|
||||
return new AddressBookWrapper(CloneComObject());
|
||||
}
|
||||
|
||||
IAddressBook IAddressBook.Clone()
|
||||
{
|
||||
return new AddressBookWrapper(CloneComObject());
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach(dynamic item in _item.Items)
|
||||
foreach(dynamic item in _item.Items.ComEnum())
|
||||
{
|
||||
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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Utils;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
public override string ToString() { return "Appointment: " + Subject; }
|
||||
|
||||
protected override PropertyAccessor GetPropertyAccessor()
|
||||
{
|
||||
return _item.PropertyAccessor;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#region IAppointmentItem implementation
|
||||
|
||||
public DateTime Start
|
||||
{
|
||||
@ -58,6 +52,29 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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
|
||||
{
|
||||
get { return _item.Body; }
|
||||
@ -70,45 +87,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
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 ContactItemWrapper : OutlookWrapper<ContactItem>, IContactItem
|
||||
class ContactItemWrapper : OutlookItemWrapper<NSOutlook.ContactItem>, IContactItem
|
||||
{
|
||||
internal ContactItemWrapper(ContactItem item)
|
||||
internal ContactItemWrapper(NSOutlook.ContactItem item)
|
||||
:
|
||||
base(item)
|
||||
{
|
||||
}
|
||||
|
||||
protected override PropertyAccessor GetPropertyAccessor()
|
||||
{
|
||||
return _item.PropertyAccessor;
|
||||
}
|
||||
|
||||
public override string ToString() { return "Contact: " + Subject; }
|
||||
|
||||
#region IContactItem implementation
|
||||
|
||||
public string CustomerID
|
||||
@ -179,6 +172,30 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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
|
||||
|
||||
#region IItem implementation
|
||||
@ -195,49 +212,71 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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 SetPicture(string path)
|
||||
{
|
||||
_item.AddPicture(path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,95 +19,64 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Utils;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
protected override PropertyAccessor GetPropertyAccessor()
|
||||
{
|
||||
return _item.PropertyAccessor;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#region IDistributionList implementation
|
||||
|
||||
public string SMTPAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
PropertyAccessor props = _item.PropertyAccessor;
|
||||
try
|
||||
{
|
||||
return (string)props.GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(props);
|
||||
}
|
||||
return (string)GetProperty(OutlookConstants.PR_EMAIL1EMAILADDRESS);
|
||||
}
|
||||
set
|
||||
{
|
||||
string displayName = DLName + " (" + value + ")";
|
||||
byte[] oneOffId = CreateOneOffMemberId(DLName, "SMTP", value);
|
||||
PropertyAccessor props = _item.PropertyAccessor;
|
||||
try
|
||||
{
|
||||
props.SetProperties(
|
||||
new string[]
|
||||
{
|
||||
OutlookConstants.PR_EMAIL1DISPLAYNAME,
|
||||
OutlookConstants.PR_EMAIL1EMAILADDRESS,
|
||||
OutlookConstants.PR_EMAIL1ADDRESSTYPE,
|
||||
OutlookConstants.PR_EMAIL1ORIGINALDISPLAYNAME,
|
||||
OutlookConstants.PR_EMAIL1ORIGINALENTRYID
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
DLName,
|
||||
value,
|
||||
"SMTP",
|
||||
value,
|
||||
oneOffId
|
||||
}
|
||||
);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(props);
|
||||
}
|
||||
|
||||
SetProperties(
|
||||
new string[]
|
||||
{
|
||||
OutlookConstants.PR_EMAIL1DISPLAYNAME,
|
||||
OutlookConstants.PR_EMAIL1EMAILADDRESS,
|
||||
OutlookConstants.PR_EMAIL1ADDRESSTYPE,
|
||||
OutlookConstants.PR_EMAIL1ORIGINALDISPLAYNAME,
|
||||
OutlookConstants.PR_EMAIL1ORIGINALENTRYID
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
DLName,
|
||||
value,
|
||||
"SMTP",
|
||||
value,
|
||||
oneOffId
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public IUserProperty<Type> GetUserProperty<Type>(string name, bool create = false)
|
||||
public string DLName
|
||||
{
|
||||
return UserPropertyWrapper<Type>.Get(_item.UserProperties, name, create);
|
||||
get { return _item.DLName; }
|
||||
set { _item.DLName = value; }
|
||||
}
|
||||
|
||||
public void Delete() { _item.Delete(); }
|
||||
public void Save() { _item.Save(); }
|
||||
|
||||
public void AddMember(IItem item)
|
||||
{
|
||||
if (item is IContactItem)
|
||||
{
|
||||
string email = ((IContactItem)item).Email1Address;
|
||||
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);
|
||||
AddContactMember((IContactItem)item);
|
||||
}
|
||||
else if (item is IDistributionList)
|
||||
{
|
||||
@ -115,8 +84,22 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddDistributionListMember(IDistributionList member)
|
||||
@ -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
|
||||
// groups (e.g. 'Germany' and 'Sales Germany' fails to find Germany). Patch the member
|
||||
// tables explicitly.
|
||||
PropertyAccessor props = _item.PropertyAccessor;
|
||||
object[] members = props.GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS);
|
||||
object[] oneOffMembers = props.GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS);
|
||||
object[] members = (object[])GetProperty(OutlookConstants.PR_DISTLIST_MEMBERS);
|
||||
object[] oneOffMembers = (object[])GetProperty(OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS);
|
||||
|
||||
// Create the new member ids
|
||||
byte[] memberId = CreateMemberId(member);
|
||||
@ -163,7 +145,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
newOneOffMembers[existingIndex] = oneOffMemberId;
|
||||
|
||||
// Write back
|
||||
props.SetProperties(
|
||||
SetProperties(
|
||||
new string[] { OutlookConstants.PR_DISTLIST_MEMBERS, OutlookConstants.PR_DISTLIST_ONEOFFMEMBERS },
|
||||
new object[] { newMembers, newOneOffMembers }
|
||||
);
|
||||
@ -178,7 +160,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
List<byte> id = new List<byte>();
|
||||
id.AddRange(PREFIX_MEMBER_ID);
|
||||
id.AddRange(StringUtil.HexToBytes(member.EntryId));
|
||||
id.AddRange(StringUtil.HexToBytes(member.EntryID));
|
||||
return id.ToArray();
|
||||
}
|
||||
|
||||
@ -213,14 +195,27 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
|
||||
#endregion
|
||||
|
||||
public override string ToString() { return "DistributionList: " + DLName; }
|
||||
#region Wrapper methods
|
||||
|
||||
public string DLName
|
||||
protected override NSOutlook.UserProperties GetUserProperties()
|
||||
{
|
||||
get { return _item.DLName; }
|
||||
set { _item.DLName = value; }
|
||||
return _item.UserProperties;
|
||||
}
|
||||
|
||||
protected override NSOutlook.PropertyAccessor GetPropertyAccessor()
|
||||
{
|
||||
return _item.PropertyAccessor;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "DistributionList: " + DLName;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IItem implementation
|
||||
|
||||
public string Body
|
||||
{
|
||||
get { return _item.Body; }
|
||||
@ -233,40 +228,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
set { _item.Subject = value; }
|
||||
}
|
||||
|
||||
public IFolder Parent { get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); } }
|
||||
public string ParentEntryId
|
||||
public void Save() { _item.Save(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
public IStore Store { get { return StoreWrapper.Wrap(_item.Parent?.Store); } }
|
||||
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
|
||||
{
|
||||
// TODO: release needed
|
||||
return _item.Parent?.Store?.StoreID;
|
||||
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
|
||||
{
|
||||
// TODO: release needed
|
||||
return _item.Parent?.Store?.DisplayName;
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
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
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -23,39 +22,66 @@ using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public string FullFolderPath { get { return _item.FullFolderPath; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,17 +95,20 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
object parent = current.Parent;
|
||||
com.Add(parent);
|
||||
if (!(parent is Folder))
|
||||
object parent = com.Add(current.Parent);
|
||||
|
||||
current = parent as NSOutlook.Folder;
|
||||
if (current == null)
|
||||
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 string StoreId
|
||||
public IStore GetStore() { return Mapping.Wrap(_item.Store); }
|
||||
|
||||
public string StoreID
|
||||
{
|
||||
get
|
||||
{
|
||||
using (IStore store = Store)
|
||||
using (IStore store = GetStore())
|
||||
{
|
||||
return store.StoreID;
|
||||
}
|
||||
@ -109,7 +139,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
using (IStore store = Store)
|
||||
using (IStore store = GetStore())
|
||||
{
|
||||
return store.DisplayName;
|
||||
}
|
||||
@ -118,119 +148,20 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
|
||||
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)
|
||||
{
|
||||
this._items = _folder.Items;
|
||||
if (field != null)
|
||||
{
|
||||
this._items.Sort("[" + field + "]", descending);
|
||||
}
|
||||
this._enum = _items.GetEnumerator();
|
||||
}
|
||||
|
||||
public ItemType Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_last != null)
|
||||
{
|
||||
_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
|
||||
public IItems Items
|
||||
{
|
||||
get
|
||||
{
|
||||
return new IItemsEnumerable<IItem>(_item, null, false);
|
||||
return new ItemsWrapper(this);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IItem> ItemsSorted(string field, bool descending)
|
||||
{
|
||||
return new IItemsEnumerable<IItem>(_item, field, descending);
|
||||
}
|
||||
|
||||
public IItem GetItemById(string entryId)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (IStore store = Store)
|
||||
using (IStore store = GetStore())
|
||||
{
|
||||
return store.GetItemFromID(entryId);
|
||||
}
|
||||
@ -270,77 +201,76 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
return new SearchWrapper<ItemType>(_item.Items);
|
||||
}
|
||||
|
||||
#region Subfolders
|
||||
|
||||
public IEnumerable<FolderType> GetSubFolders<FolderType>()
|
||||
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)
|
||||
where FolderType : IFolder
|
||||
{
|
||||
// Fetching the folder by name throws an exception if not found, loop and find
|
||||
// to prevent exceptions in the log
|
||||
MAPIFolder sub = null;
|
||||
foreach(MAPIFolder folder in _item.Folders)
|
||||
// to prevent exceptions in the log.
|
||||
// Don't release the items in RawEnum, they are release manually or handed to WrapFolders.
|
||||
NSOutlook.Folder sub = null;
|
||||
foreach(NSOutlook.Folder folder in _item.Folders.ComEnum(false))
|
||||
{
|
||||
if (folder.Name == name)
|
||||
{
|
||||
sub = folder;
|
||||
break;
|
||||
break; // TODO: does this prevent the rest of the objects from getting released?
|
||||
}
|
||||
else
|
||||
{
|
||||
ComRelease.Release(folder);
|
||||
}
|
||||
}
|
||||
if (sub == null)
|
||||
return default(FolderType);
|
||||
return WrapFolder<FolderType>(sub);
|
||||
return sub.Wrap<FolderType>();
|
||||
}
|
||||
|
||||
public FolderType CreateFolder<FolderType>(string name)
|
||||
where FolderType : IFolder
|
||||
{
|
||||
Folders folders = _item.Folders;
|
||||
try
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
NSOutlook.Folders folders = com.Add(_item.Folders);
|
||||
if (typeof(FolderType) == typeof(IFolder))
|
||||
{
|
||||
return WrapFolder<FolderType>(folders.Add(name));
|
||||
return folders.Add(name).Wrap<FolderType>();
|
||||
}
|
||||
else if (typeof(FolderType) == typeof(IAddressBook))
|
||||
{
|
||||
MAPIFolder newFolder = folders.Add(name, OlDefaultFolders.olFolderContacts);
|
||||
NSOutlook.MAPIFolder newFolder = folders.Add(name, NSOutlook.OlDefaultFolders.olFolderContacts);
|
||||
newFolder.ShowAsOutlookAB = true;
|
||||
return WrapFolder<FolderType>(newFolder);
|
||||
return newFolder.Wrap<FolderType>();
|
||||
}
|
||||
else
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(folders);
|
||||
}
|
||||
}
|
||||
|
||||
private FolderType WrapFolder<FolderType>(MAPIFolder folder)
|
||||
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();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public IStorageItem GetStorageItem(string name)
|
||||
{
|
||||
StorageItem item = _item.GetStorage(name, OlStorageIdentifierType.olIdentifyBySubject);
|
||||
NSOutlook.StorageItem item = _item.GetStorage(name, NSOutlook.OlStorageIdentifierType.olIdentifyBySubject);
|
||||
if (item == null)
|
||||
return null;
|
||||
return new StorageItemWrapper(item);
|
||||
@ -355,16 +285,12 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
public ItemType Create<ItemType>()
|
||||
where ItemType : IItem
|
||||
{
|
||||
Items items = _item.Items;
|
||||
try
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
NSOutlook.Items items = com.Add(_item.Items);
|
||||
object item = items.Add(Mapping.OutlookItemType<ItemType>());
|
||||
return Mapping.Wrap<ItemType>(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(items);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -411,14 +337,14 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
_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
|
||||
{
|
||||
if (_beforeItemMove != null)
|
||||
{
|
||||
using (IItem itemWrapped = Mapping.Wrap<IItem>(item))
|
||||
using (IFolder targetWrapped = Mapping.Wrap<IFolder>(target))
|
||||
using (IItem itemWrapped = Mapping.Wrap<IItem>(item, false))
|
||||
using (IFolder targetWrapped = Mapping.Wrap<IFolder>(target, false))
|
||||
{
|
||||
if (itemWrapped != null && targetWrapped != null)
|
||||
{
|
||||
@ -435,5 +361,15 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
|
||||
#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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Utils;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override string ToString() { return "Mail: " + Subject; }
|
||||
public override string ToString()
|
||||
{
|
||||
return "Mail:" + Subject;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region IItem implementation
|
||||
|
||||
public string Body
|
||||
{
|
||||
@ -53,37 +121,53 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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
|
||||
{
|
||||
Folder parent = (Folder)_item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
return Mapping.Wrap<IFolder>(_item.Parent as NSOutlook.Folder);
|
||||
}
|
||||
}
|
||||
|
||||
public string ParentEntryID
|
||||
{
|
||||
get
|
||||
{
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
return StoreWrapper.Wrap(parent?.Store);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
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
|
||||
{
|
||||
Folder parent = (Folder)_item.Parent;
|
||||
Store store = null;
|
||||
try
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
store = parent?.Store;
|
||||
return store?.StoreID;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
ComRelease.Release(store);
|
||||
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||
NSOutlook.Store store = com.Add(parent?.Store);
|
||||
return store.StoreID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,76 +176,17 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = (Folder)_item.Parent;
|
||||
Store store = null;
|
||||
try
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
store = parent?.Store;
|
||||
return store?.DisplayName;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
ComRelease.Release(store);
|
||||
NSOutlook.Folder parent = com.Add(_item.Parent);
|
||||
NSOutlook.Store store = com.Add(parent?.Store);
|
||||
return store.StoreID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SenderEmailAddress
|
||||
{
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
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
|
||||
{
|
||||
// TODO: a clean up is needed, move as much as possible to Wrappers.cs
|
||||
public static class Mapping
|
||||
{
|
||||
|
||||
@ -32,40 +33,42 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
/// </summary>
|
||||
/// <param name="o">The Outlook object.</param>
|
||||
/// <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)
|
||||
return null;
|
||||
|
||||
IBase wrapper = CreateWrapper(o);
|
||||
IBase wrapper = CreateWrapper(o, mustRelease);
|
||||
if (wrapper != null)
|
||||
wrapper.MustRelease = mustRelease;
|
||||
ComRelease.LogWrapper(o, wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private static IBase CreateWrapper(object o)
|
||||
private static IBase CreateWrapper(object o, bool mustRelease)
|
||||
{
|
||||
// TODO: switch on o.Class
|
||||
if (o is MailItem)
|
||||
return new MailItemWrapper((MailItem)o);
|
||||
if (o is AppointmentItem)
|
||||
return new AppointmentItemWrapper((AppointmentItem)o);
|
||||
if (o is Folder)
|
||||
return new FolderWrapper((Folder)o);
|
||||
if (o is ContactItem)
|
||||
return new ContactItemWrapper((ContactItem)o);
|
||||
if (o is DistListItem)
|
||||
return new DistributionListWrapper((DistListItem)o);
|
||||
if (o is NoteItem)
|
||||
return new NoteItemWrapper((NoteItem)o);
|
||||
if (o is TaskItem)
|
||||
return new TaskItemWrapper((TaskItem)o);
|
||||
|
||||
// TODO: support this?
|
||||
if (o is ReportItem)
|
||||
return null;
|
||||
if (o is NSOutlook.MailItem)
|
||||
return new MailItemWrapper((NSOutlook.MailItem)o);
|
||||
if (o is NSOutlook.AppointmentItem)
|
||||
return new AppointmentItemWrapper((NSOutlook.AppointmentItem)o);
|
||||
if (o is NSOutlook.Folder)
|
||||
return new FolderWrapper((NSOutlook.Folder)o);
|
||||
if (o is NSOutlook.ContactItem)
|
||||
return new ContactItemWrapper((NSOutlook.ContactItem)o);
|
||||
if (o is NSOutlook.DistListItem)
|
||||
return new DistributionListWrapper((NSOutlook.DistListItem)o);
|
||||
if (o is NSOutlook.NoteItem)
|
||||
return new NoteItemWrapper((NSOutlook.NoteItem)o);
|
||||
if (o is NSOutlook.TaskItem)
|
||||
return new TaskItemWrapper((NSOutlook.TaskItem)o);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -75,59 +78,64 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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)
|
||||
where Type : IBase
|
||||
{
|
||||
IBase wrapped = Wrap(o, mustRelease);
|
||||
if (wrapped is Type)
|
||||
return (Type)wrapped;
|
||||
|
||||
// Release if required
|
||||
if (wrapped != null)
|
||||
wrapped.Dispose();
|
||||
return default(Type);
|
||||
}
|
||||
|
||||
public static OlItemType OutlookItemType<ItemType>()
|
||||
public static NSOutlook.OlItemType OutlookItemType<ItemType>()
|
||||
where ItemType: IItem
|
||||
{
|
||||
Type type = typeof(ItemType);
|
||||
if (type == typeof(IContactItem))
|
||||
return OlItemType.olContactItem;
|
||||
return NSOutlook.OlItemType.olContactItem;
|
||||
if (type == typeof(IDistributionList))
|
||||
return OlItemType.olDistributionListItem;
|
||||
return NSOutlook.OlItemType.olDistributionListItem;
|
||||
throw new NotImplementedException(); // TODO
|
||||
}
|
||||
|
||||
public static OlUserPropertyType OutlookPropertyType<PropType>()
|
||||
public static NSOutlook.OlUserPropertyType OutlookPropertyType<PropType>()
|
||||
{
|
||||
Type type = typeof(PropType);
|
||||
if (type == typeof(string))
|
||||
return OlUserPropertyType.olText;
|
||||
return NSOutlook.OlUserPropertyType.olText;
|
||||
if (type == typeof(DateTime))
|
||||
return OlUserPropertyType.olDateTime;
|
||||
return NSOutlook.OlUserPropertyType.olDateTime;
|
||||
if (type == typeof(int))
|
||||
return OlUserPropertyType.olInteger;
|
||||
return NSOutlook.OlUserPropertyType.olInteger;
|
||||
if (type.IsEnum)
|
||||
return OlUserPropertyType.olInteger;
|
||||
return NSOutlook.OlUserPropertyType.olInteger;
|
||||
if (type == typeof(string[]))
|
||||
return OlUserPropertyType.olKeywords;
|
||||
return NSOutlook.OlUserPropertyType.olKeywords;
|
||||
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
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Acacia.Utils;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public override string ToString() { return "Note: " + Subject; }
|
||||
public override string ToString()
|
||||
{
|
||||
return "Note:" + Subject;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region IItem implementation
|
||||
|
||||
public string Body
|
||||
{
|
||||
@ -50,48 +62,78 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
public string Subject
|
||||
{
|
||||
get { return _item.Subject; }
|
||||
set { throw new NotSupportedException(); }
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException("NoteItem does not support setting body");
|
||||
}
|
||||
}
|
||||
|
||||
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(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
using Acacia.Features.DebugSupport;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -23,56 +22,45 @@ using Acacia.Utils;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for Outlook wrapper implementations
|
||||
/// </summary>
|
||||
abstract public class OutlookWrapper<ItemType> : DisposableWrapper
|
||||
abstract class OutlookWrapper<ItemType> : ComWrapper<ItemType>
|
||||
{
|
||||
|
||||
#region Construction / Destruction
|
||||
|
||||
protected ItemType _item;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a wrapper.
|
||||
/// </summary>
|
||||
internal OutlookWrapper(ItemType item)
|
||||
{
|
||||
this._item = item;
|
||||
}
|
||||
|
||||
~OutlookWrapper()
|
||||
internal OutlookWrapper(ItemType item) : base(item)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DoRelease()
|
||||
{
|
||||
// Always release props, as we allocated that
|
||||
if (_props != null)
|
||||
{
|
||||
ComRelease.Release(_props);
|
||||
_props = null;
|
||||
}
|
||||
|
||||
if (MustRelease)
|
||||
{
|
||||
if (_item != null)
|
||||
{
|
||||
ComRelease.Release(_item);
|
||||
_item = default(ItemType);
|
||||
}
|
||||
}
|
||||
base.DoRelease();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties implementation
|
||||
|
||||
private PropertyAccessor _props;
|
||||
// Assigned in Props, released in DoRelease
|
||||
private NSOutlook.PropertyAccessor _props;
|
||||
|
||||
private PropertyAccessor Props
|
||||
private NSOutlook.PropertyAccessor Props
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -88,7 +76,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
/// Returns the wrapped item's property accessor.
|
||||
/// </summary>
|
||||
/// <returns>The property accessor. The caller is responsible for disposing this.</returns>
|
||||
abstract protected PropertyAccessor GetPropertyAccessor();
|
||||
abstract protected NSOutlook.PropertyAccessor GetPropertyAccessor();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -112,7 +100,14 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
get
|
||||
{
|
||||
return Props.GetProperty(OutlookConstants.PR_ATTR_HIDDEN);
|
||||
try
|
||||
{
|
||||
return Props.GetProperty(OutlookConstants.PR_ATTR_HIDDEN);
|
||||
}
|
||||
catch(System.Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
@ -120,30 +115,6 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
try
|
||||
@ -153,7 +124,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
return null;
|
||||
return val;
|
||||
}
|
||||
catch(System.Exception) { return null; } // TODO: is this fine everywhere?
|
||||
catch(System.Exception) { return null; }
|
||||
}
|
||||
|
||||
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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Utils;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
class SearchWrapper<ItemType> : ISearch<ItemType>
|
||||
class SearchWrapper<ItemType> : ComWrapper<NSOutlook.Items>, ISearch<ItemType>
|
||||
where ItemType : IItem
|
||||
{
|
||||
private interface SearchTerm
|
||||
@ -151,11 +151,13 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
}
|
||||
|
||||
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)
|
||||
@ -174,31 +176,42 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
|
||||
public IEnumerable<ItemType> Search(int maxResults)
|
||||
{
|
||||
List<ItemType> values = new List<ItemType>();
|
||||
string filter = MakeFilter();
|
||||
object value = _items.Find(filter);
|
||||
|
||||
int count = 0;
|
||||
object value = _item.Find(filter);
|
||||
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);
|
||||
if (wrapped != null)
|
||||
{
|
||||
values.Add(wrapped);
|
||||
try
|
||||
{
|
||||
yield return wrapped;
|
||||
}
|
||||
finally
|
||||
{
|
||||
wrapped.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Release if not returned. Keep looping to release any others
|
||||
ComRelease.Release(value);
|
||||
}
|
||||
value = _items.FindNext();
|
||||
value = _item.FindNext();
|
||||
++count;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public ItemType SearchOne()
|
||||
{
|
||||
object value = _items.Find(MakeFilter());
|
||||
// Wrap manages com object in value
|
||||
object value = _item.Find(MakeFilter());
|
||||
if (value == null)
|
||||
return default(ItemType);
|
||||
return Mapping.Wrap<ItemType>(value);
|
||||
|
@ -15,31 +15,44 @@
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
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
|
||||
{
|
||||
public class StorageItemWrapper : OutlookWrapper<StorageItem>, IStorageItem
|
||||
class StorageItemWrapper : OutlookItemWrapper<NSOutlook.StorageItem>, IStorageItem
|
||||
{
|
||||
public StorageItemWrapper(StorageItem item)
|
||||
public StorageItemWrapper(NSOutlook.StorageItem 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;
|
||||
}
|
||||
|
||||
public override string ToString() { return "StorageItem"; }
|
||||
public override string ToString()
|
||||
{
|
||||
return "StorageItem";
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region IItem implementation
|
||||
|
||||
public string Body
|
||||
{
|
||||
@ -53,45 +66,72 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
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(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Utils;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
NameSpace nmspace = _store.Session;
|
||||
try
|
||||
{
|
||||
using (ComRelease com = new ComRelease())
|
||||
{
|
||||
NSOutlook.NameSpace nmspace = com.Add(_item.Session);
|
||||
|
||||
// Get the item; the wrapper manages it
|
||||
object o = nmspace.GetItemFromID(id);
|
||||
return Mapping.Wrap<IItem>(o);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(nmspace);
|
||||
}
|
||||
}
|
||||
|
||||
public string DisplayName { get { return _store.DisplayName; } }
|
||||
public string StoreID { get { return _store.StoreID; } }
|
||||
public string DisplayName { get { return _item.DisplayName; } }
|
||||
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
|
||||
|
||||
using Acacia.Utils;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
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
|
||||
{
|
||||
public class TaskItemWrapper : OutlookWrapper<TaskItem>, ITaskItem
|
||||
class TaskItemWrapper : OutlookItemWrapper<NSOutlook.TaskItem>, ITaskItem
|
||||
{
|
||||
internal TaskItemWrapper(TaskItem item)
|
||||
internal TaskItemWrapper(NSOutlook.TaskItem 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;
|
||||
}
|
||||
|
||||
public override string ToString() { return "Task: " + Subject; }
|
||||
public override string ToString()
|
||||
{
|
||||
return "Task:" + Subject;
|
||||
}
|
||||
|
||||
#region Properties
|
||||
#endregion
|
||||
|
||||
#region IItem implementation
|
||||
|
||||
public string Body
|
||||
{
|
||||
@ -50,48 +63,75 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
public string 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(); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBase implementation
|
||||
|
||||
public string EntryID { get { return _item.EntryID; } }
|
||||
|
||||
public IFolder Parent
|
||||
{
|
||||
get { return (IFolder)Mapping.Wrap(_item.Parent as Folder); }
|
||||
}
|
||||
public string ParentEntryId
|
||||
{
|
||||
get
|
||||
{
|
||||
Folder parent = _item.Parent;
|
||||
try
|
||||
// The wrapper manages the returned folder
|
||||
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;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ComRelease.Release(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.Text;
|
||||
using System.Xml.Linq;
|
||||
using Outlook = Microsoft.Office.Interop.Outlook;
|
||||
using Office = Microsoft.Office.Core;
|
||||
using Acacia.Features;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
@ -29,27 +27,23 @@ using Acacia.UI;
|
||||
using Acacia.ZPush;
|
||||
using System.Globalization;
|
||||
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
|
||||
{
|
||||
public partial class ThisAddIn
|
||||
{
|
||||
|
||||
public static ThisAddIn Instance
|
||||
public static IAddIn Instance
|
||||
{
|
||||
get;
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
@ -69,15 +63,20 @@ namespace Acacia
|
||||
private set;
|
||||
}
|
||||
|
||||
public FeatureType GetFeature<FeatureType>()
|
||||
where FeatureType : Feature
|
||||
private MailEvents _mailEvents;
|
||||
public MailEvents MailEvents
|
||||
{
|
||||
foreach(Feature feature in Features)
|
||||
get
|
||||
{
|
||||
if (feature is FeatureType)
|
||||
return (FeatureType)feature;
|
||||
if (_mailEvents == null)
|
||||
{
|
||||
if (GlobalOptions.INSTANCE.HookItemEvents)
|
||||
{
|
||||
_mailEvents = new MailEvents(Instance);
|
||||
}
|
||||
}
|
||||
return _mailEvents;
|
||||
}
|
||||
return default(FeatureType);
|
||||
}
|
||||
|
||||
#region Startup / Shutdown
|
||||
@ -100,16 +99,12 @@ namespace Acacia
|
||||
return;
|
||||
}
|
||||
|
||||
Instance = this;
|
||||
Instance = new AddInWrapper(this);
|
||||
|
||||
// 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);
|
||||
|
||||
// Create a dispatcher
|
||||
_dispatcher = new Control();
|
||||
_dispatcher.CreateControl();
|
||||
|
||||
// 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
|
||||
if (SynchronizationContext.Current == null)
|
||||
@ -118,7 +113,7 @@ namespace Acacia
|
||||
}
|
||||
|
||||
// Create the watcher
|
||||
Watcher = new ZPushWatcher(Application);
|
||||
Watcher = new ZPushWatcher(Instance);
|
||||
OutlookUI.Watcher = Watcher;
|
||||
|
||||
// Allow to features to register whatever they need
|
||||
@ -151,11 +146,17 @@ namespace Acacia
|
||||
|
||||
// Start watching events
|
||||
if (DebugOptions.GetOption(null, DebugOptions.WATCHER_ENABLED))
|
||||
{
|
||||
((AddInWrapper)Instance).Start();
|
||||
Watcher.Start();
|
||||
}
|
||||
|
||||
// Done
|
||||
Logger.Instance.Debug(this, "Startup done");
|
||||
Acacia.Features.DebugSupport.Statistics.StartupTime.Stop();
|
||||
foreach (Feature feature in Features)
|
||||
feature.AfterStartup();
|
||||
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@ -172,6 +173,7 @@ namespace Acacia
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: is any management of Pages needed here?
|
||||
Pages.Add(new SettingsPage(Features.ToArray()), Properties.Resources.ThisAddIn_Title);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
|
@ -224,23 +224,22 @@ namespace Acacia.UI
|
||||
public List<GABUser> Lookup(string text, int max)
|
||||
{
|
||||
// Begin GAB lookup, search on full name or username
|
||||
ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>();
|
||||
ISearchOperator oper = search.AddOperator(SearchOperator.Or);
|
||||
oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%");
|
||||
oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%");
|
||||
|
||||
// Fetch the results up to the limit.
|
||||
// TODO: make limit a property
|
||||
List<GABUser> users = new List<GABUser>();
|
||||
foreach (IContactItem result in search.Search(max))
|
||||
using (ISearch<IContactItem> search = _gab.Contacts.Search<IContactItem>())
|
||||
{
|
||||
using (result)
|
||||
ISearchOperator oper = search.AddOperator(SearchOperator.Or);
|
||||
oper.AddField("urn:schemas:contacts:cn").SetOperation(SearchOperation.Like, text + "%");
|
||||
oper.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Like, text + "%");
|
||||
|
||||
// Fetch the results up to the limit.
|
||||
// TODO: make limit a property?
|
||||
List<GABUser> users = new List<GABUser>();
|
||||
foreach (IContactItem result in search.Search(max))
|
||||
{
|
||||
users.Add(new GABUser(result.FullName, result.CustomerID));
|
||||
}
|
||||
}
|
||||
|
||||
return users;
|
||||
return users;
|
||||
}
|
||||
}
|
||||
|
||||
public GABUser LookupExact(string username)
|
||||
@ -252,13 +251,11 @@ namespace Acacia.UI
|
||||
search.AddField("urn:schemas:contacts:customerid").SetOperation(SearchOperation.Equal, username);
|
||||
|
||||
// Fetch the result, if any.
|
||||
// TODO: make a SearchOne method?
|
||||
List<GABUser> users = new List<GABUser>();
|
||||
foreach (IContactItem result in search.Search(1))
|
||||
{
|
||||
using (result)
|
||||
{
|
||||
return new GABUser(result.FullName, result.CustomerID);
|
||||
}
|
||||
return new GABUser(result.FullName, result.CustomerID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
/// 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/>.
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Microsoft.Office.Core;
|
||||
using stdole;
|
||||
using System;
|
||||
@ -35,105 +37,19 @@ namespace Acacia.UI.Outlook
|
||||
{
|
||||
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)
|
||||
{
|
||||
Images = new ImageList();
|
||||
Images.ColorDepth = ColorDepth.Depth32Bit;
|
||||
Images.ImageSize = new Size(16, 16);
|
||||
|
||||
CommandBars cmdBars = ThisAddIn.Instance.Application.ActiveWindow().CommandBars;
|
||||
foreach (string id in icons)
|
||||
using (IExplorer explorer = ThisAddIn.Instance.GetActiveExplorer())
|
||||
using (ICommandBars cmdBars = explorer.GetCommandBars())
|
||||
{
|
||||
IPictureDisp pict = cmdBars.GetImageMso(id, Images.ImageSize.Width, Images.ImageSize.Height);
|
||||
var img = GetBitmapFromHBitmap2(new IntPtr(pict.Handle));
|
||||
Images.Images.Add(img);
|
||||
foreach (string id in icons)
|
||||
{
|
||||
Images.Images.Add(cmdBars.GetMso(id).GetImage(Images.ImageSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
@ -23,7 +23,6 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.UI
|
||||
{
|
||||
@ -48,19 +47,19 @@ namespace Acacia.UI
|
||||
{
|
||||
get
|
||||
{
|
||||
return ThisAddIn.Instance.Application;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public OlObjectClass Class
|
||||
public Microsoft.Office.Interop.Outlook.OlObjectClass Class
|
||||
{
|
||||
get
|
||||
{
|
||||
return OlObjectClass.olApplication;
|
||||
return Microsoft.Office.Interop.Outlook.OlObjectClass.olApplication;
|
||||
}
|
||||
}
|
||||
|
||||
public NameSpace Session
|
||||
public Microsoft.Office.Interop.Outlook.NameSpace Session
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -68,7 +67,7 @@ namespace Acacia.UI
|
||||
}
|
||||
}
|
||||
|
||||
dynamic PropertyPageSite.Parent
|
||||
dynamic Microsoft.Office.Interop.Outlook.PropertyPageSite.Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -25,11 +25,12 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.InteropServices;
|
||||
using Acacia.Features;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
|
||||
namespace Acacia.UI
|
||||
{
|
||||
[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>();
|
||||
|
||||
@ -78,8 +79,8 @@ namespace Acacia.UI
|
||||
Dirty = _featuresDirty.Values.Aggregate((a, b) => a | b);
|
||||
}
|
||||
|
||||
private Microsoft.Office.Interop.Outlook.PropertyPageSite _propertyPageSite;
|
||||
public Microsoft.Office.Interop.Outlook.PropertyPageSite PropertyPageSite
|
||||
private NSOutlook.PropertyPageSite _propertyPageSite;
|
||||
public NSOutlook.PropertyPageSite PropertyPageSite
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -96,7 +97,8 @@ namespace Acacia.UI
|
||||
System.Reflection.MethodInfo methodInfo = oleObjectType.GetMethod("GetClientSite");
|
||||
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;
|
||||
}
|
||||
|
@ -34,6 +34,12 @@ namespace Acacia.Utils
|
||||
return t;
|
||||
}
|
||||
|
||||
public Type Remove<Type>(Type t)
|
||||
{
|
||||
objects.Remove(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
if (o == null)
|
||||
if (o == null || !Marshal.IsComObject(o))
|
||||
return;
|
||||
|
||||
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
|
||||
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||
@ -15,7 +15,6 @@
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Acacia.Features.DebugSupport;
|
||||
using Acacia.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -23,15 +22,13 @@ using System.Text;
|
||||
using System.Threading;
|
||||
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>
|
||||
/// Creates a wrapper.
|
||||
/// </summary>
|
||||
internal DisposableWrapper()
|
||||
protected DisposableWrapper()
|
||||
{
|
||||
Interlocked.Increment(ref Statistics.CreatedWrappers);
|
||||
this._createdTrace = new System.Diagnostics.StackTrace();
|
||||
@ -43,9 +40,12 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Logger.Instance.Warning(this, "Undisposed wrapper: {0}", _createdTrace);
|
||||
Dispose();
|
||||
// Don't count auto disposals
|
||||
Interlocked.Decrement(ref Statistics.DisposedWrappers);
|
||||
// Dispose, but don't count auto disposals, so the stats show it.
|
||||
DoRelease();
|
||||
}
|
||||
else
|
||||
{
|
||||
--typeCounts[GetType()];
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,11 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (!typeCounts.ContainsKey(GetType()))
|
||||
typeCounts.Add(GetType(), 1);
|
||||
else
|
||||
++typeCounts[GetType()];
|
||||
|
||||
Logger.Instance.TraceExtra(this, "Disposing wrapper: {0}", new System.Diagnostics.StackTrace());
|
||||
_isDisposed = true;
|
||||
Interlocked.Increment(ref Statistics.DisposedWrappers);
|
||||
@ -63,12 +68,7 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
}
|
||||
}
|
||||
|
||||
public bool MustRelease
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
abstract protected void DoRelease();
|
||||
}
|
||||
|
||||
}
|
@ -28,17 +28,19 @@ namespace Acacia.Utils
|
||||
{
|
||||
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)
|
||||
{
|
||||
string type = (string)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE_ORIG);
|
||||
if (string.IsNullOrEmpty(type))
|
||||
return null;
|
||||
return (OutlookConstants.SyncType)int.Parse(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
int type = (int)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE);
|
||||
return (OutlookConstants.SyncType)type;
|
||||
int? type = (int?)folder.GetProperty(OutlookConstants.PR_EAS_SYNCTYPE);
|
||||
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
|
||||
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -47,20 +46,16 @@ namespace Acacia.Utils
|
||||
public event MailResponseEventHandler Respond;
|
||||
|
||||
public event MailResponseEventHandler Reply;
|
||||
private void OnReply(MailItem mail, MailItem response)
|
||||
private void OnReply(IMailItem mail, IMailItem response)
|
||||
{
|
||||
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)
|
||||
Reply(mailWrapped, responseWrapped);
|
||||
if (Respond != null)
|
||||
Respond(mailWrapped, responseWrapped);
|
||||
}
|
||||
if (Reply != null)
|
||||
Reply(mail, response);
|
||||
if (Respond != null)
|
||||
Respond(mail, response);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@ -70,20 +65,16 @@ namespace Acacia.Utils
|
||||
}
|
||||
|
||||
public event MailResponseEventHandler ReplyAll;
|
||||
private void OnReplyAll(MailItem mail, MailItem response)
|
||||
private void OnReplyAll(IMailItem mail, IMailItem response)
|
||||
{
|
||||
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)
|
||||
ReplyAll(mailWrapped, responseWrapped);
|
||||
if (Respond != null)
|
||||
Respond(mailWrapped, responseWrapped);
|
||||
}
|
||||
if (ReplyAll != null)
|
||||
ReplyAll(mail, response);
|
||||
if (Respond != null)
|
||||
Respond(mail, response);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@ -93,20 +84,16 @@ namespace Acacia.Utils
|
||||
}
|
||||
|
||||
public event MailResponseEventHandler Forward;
|
||||
private void OnForward(MailItem mail, MailItem response)
|
||||
private void OnForward(IMailItem mail, IMailItem response)
|
||||
{
|
||||
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)
|
||||
Forward(mailWrapped, responseWrapped);
|
||||
if (Respond != null)
|
||||
Respond(mailWrapped, responseWrapped);
|
||||
}
|
||||
if (Forward != null)
|
||||
Forward(mail, response);
|
||||
if (Respond != null)
|
||||
Respond(mail, response);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@ -116,16 +103,13 @@ namespace Acacia.Utils
|
||||
}
|
||||
|
||||
public event MailEventHandler Read;
|
||||
private void OnRead(MailItem mail)
|
||||
private void OnRead(IMailItem mail)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Read != null && mail != null)
|
||||
{
|
||||
using (IMailItem wrapped = Mapping.Wrap<IMailItem>(mail, false))
|
||||
{
|
||||
Read(wrapped);
|
||||
}
|
||||
Read(mail);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@ -135,17 +119,13 @@ namespace Acacia.Utils
|
||||
}
|
||||
|
||||
public event CancellableItemEventHandler BeforeDelete;
|
||||
private void OnBeforeDelete(object item, ref bool cancel)
|
||||
private void OnBeforeDelete(IItem item, ref bool cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (BeforeDelete != null && item != null)
|
||||
{
|
||||
using (IItem wrapped = Mapping.Wrap<IItem>(item, false))
|
||||
{
|
||||
if (wrapped != null)
|
||||
BeforeDelete(wrapped, ref cancel);
|
||||
}
|
||||
BeforeDelete(item, ref cancel);
|
||||
}
|
||||
}
|
||||
catch(System.Exception e)
|
||||
@ -156,17 +136,13 @@ namespace Acacia.Utils
|
||||
|
||||
// TODO: should this be CancellableMailItemEventHandler?
|
||||
public event CancellableItemEventHandler Write;
|
||||
private void OnWrite(object item, ref bool cancel)
|
||||
private void OnWrite(IItem item, ref bool cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Write != null && item != null)
|
||||
{
|
||||
using (IItem wrapped = Mapping.Wrap<IItem>(item, false))
|
||||
{
|
||||
if (wrapped != null)
|
||||
Write(wrapped, ref cancel);
|
||||
}
|
||||
Write(item, ref cancel);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@ -199,93 +175,102 @@ namespace Acacia.Utils
|
||||
|
||||
#region Implementation
|
||||
|
||||
public MailEvents(Application app)
|
||||
public MailEvents(IAddIn app)
|
||||
{
|
||||
app.ItemLoad += OnItemLoad;
|
||||
app.ItemSend += OnItemSend;
|
||||
}
|
||||
|
||||
void OnItemLoad(object item)
|
||||
private void OnItemLoad(object item)
|
||||
{
|
||||
ItemEvents_10_Event hasEvents = item as ItemEvents_10_Event;
|
||||
if (hasEvents != null)
|
||||
IItem wrapped = Wrappers.Wrap<IItem>(item, false);
|
||||
// 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 readonly MailEvents events;
|
||||
private IItem _item;
|
||||
private readonly MailEvents _events;
|
||||
|
||||
public MailEventHooker(ItemEvents_10_Event item, MailEvents events)
|
||||
public MailEventHooker(IItem item, MailEvents events)
|
||||
{
|
||||
this.item = item;
|
||||
this.events = events;
|
||||
this._item = item;
|
||||
this._events = events;
|
||||
HookEvents(true);
|
||||
}
|
||||
|
||||
protected override void DoRelease()
|
||||
{
|
||||
_item.Dispose();
|
||||
}
|
||||
|
||||
private void HookEvents(bool add)
|
||||
{
|
||||
ItemEvents_10_Event events = this.item;
|
||||
using (IItemEvents events = _item.GetEvents())
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
|
||||
if (add)
|
||||
{
|
||||
events.BeforeDelete += HandleBeforeDelete;
|
||||
events.Forward += HandleForward;
|
||||
events.Read += HandleRead;
|
||||
events.Reply += HandleReply;
|
||||
events.ReplyAll += HandleReplyAll;
|
||||
events.Unload += HandleUnload;
|
||||
events.Write += HandleWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
events.BeforeDelete -= HandleBeforeDelete;
|
||||
events.Forward -= HandleForward;
|
||||
events.Read -= HandleRead;
|
||||
events.Reply -= HandleReply;
|
||||
events.ReplyAll -= HandleReplyAll;
|
||||
events.Unload -= HandleUnload;
|
||||
events.Write -= HandleWrite;
|
||||
events.BeforeDelete += HandleBeforeDelete;
|
||||
events.Forward += HandleForward;
|
||||
events.Read += HandleRead;
|
||||
events.Reply += HandleReply;
|
||||
events.ReplyAll += HandleReplyAll;
|
||||
events.Unload += HandleUnload;
|
||||
events.Write += HandleWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
events.BeforeDelete -= HandleBeforeDelete;
|
||||
events.Forward -= HandleForward;
|
||||
events.Read -= HandleRead;
|
||||
events.Reply -= HandleReply;
|
||||
events.ReplyAll -= HandleReplyAll;
|
||||
events.Unload -= HandleUnload;
|
||||
events.Write -= HandleWrite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
events.OnForward(item as MailItem, response as MailItem);
|
||||
_events.OnForward(_item as IMailItem, response.WrapOrDefault<IMailItem>());
|
||||
}
|
||||
|
||||
private void HandleRead()
|
||||
{
|
||||
events.OnRead(item as MailItem);
|
||||
_events.OnRead(_item as IMailItem);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
events.OnReplyAll(item as MailItem, response as MailItem);
|
||||
_events.OnReplyAll(_item as IMailItem, response.WrapOrDefault<IMailItem>());
|
||||
}
|
||||
|
||||
private void HandleUnload()
|
||||
{
|
||||
// All events must be unhooked on unload, otherwise a resource leak is created.
|
||||
HookEvents(false);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Determine the base path
|
||||
string[] versionParts = ThisAddIn.Instance.Application.Version.Split('.');
|
||||
string[] versionParts = ThisAddIn.Instance.Version.Split('.');
|
||||
string versionString = versionParts[0] + "." + versionParts[1];
|
||||
string baseKeyPath = string.Format(OutlookConstants.REG_KEY_BASE, versionString);
|
||||
return RegistryUtil.OpenKeyImpl(baseKeyPath, suffix, false, permissions);
|
||||
|
@ -15,9 +15,11 @@
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using Acacia.Features;
|
||||
using Acacia.Features.DebugSupport;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Acacia.Utils
|
||||
@ -64,10 +66,29 @@ namespace Acacia.Utils
|
||||
|
||||
}
|
||||
|
||||
public interface TaskExecutor
|
||||
public abstract class TaskExecutor
|
||||
{
|
||||
string Name { get; }
|
||||
void ExecuteTask(AcaciaTask task);
|
||||
public abstract string Name { get; }
|
||||
|
||||
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
|
||||
@ -103,12 +124,12 @@ namespace Acacia.Utils
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
/// 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/>.
|
||||
///
|
||||
/// Consult LICENSE file for details
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -40,15 +41,15 @@ namespace Acacia.Utils
|
||||
while (!_tasks.IsCompleted)
|
||||
{
|
||||
AcaciaTask task = _tasks.Take();
|
||||
task.Execute();
|
||||
PerformTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteTask(AcaciaTask task)
|
||||
protected override void EnqueueTask(AcaciaTask 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();
|
||||
Logger.Instance.Trace(task.Id, "Beginning task");
|
||||
task.Execute();
|
||||
PerformTask(task);
|
||||
Logger.Instance.Info(task.Id, "Ending task: {0}ms", timer.ElapsedMilliseconds);
|
||||
// Execute another task if available and we haven't taken too long.
|
||||
} while (_tasks.Count > 0 && timer.ElapsedMilliseconds < 50);
|
||||
@ -99,7 +99,7 @@ namespace Acacia.Utils
|
||||
/// </summary>
|
||||
/// <param name="name">The name, for debugging and logging.</param>
|
||||
/// <param name="action">The action to execute</param>
|
||||
public void ExecuteTask(AcaciaTask task)
|
||||
override protected void EnqueueTask(AcaciaTask task)
|
||||
{
|
||||
if (_init == InitState.Uninitialised)
|
||||
{
|
||||
@ -112,6 +112,6 @@ namespace Acacia.Utils
|
||||
_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 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
|
||||
|
||||
using Acacia.ZPush;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -44,5 +44,123 @@ namespace Acacia.Utils
|
||||
|
||||
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,
|
||||
// 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.
|
||||
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));
|
||||
_client.DefaultRequestHeaders.Authorization = header;
|
||||
}
|
||||
@ -278,10 +278,10 @@ namespace Acacia.ZPush.Connect
|
||||
|
||||
public Response Execute(ActiveSync.RequestBase request)
|
||||
{
|
||||
string url = string.Format(ACTIVESYNC_URL, _account.ServerURL, _account.DeviceId,
|
||||
request.Command, _account.UserName, "WindowsOutlook");
|
||||
string url = string.Format(ACTIVESYNC_URL, _account.Account.ServerURL, _account.Account.DeviceId,
|
||||
request.Command, _account.Account.UserName, "WindowsOutlook");
|
||||
|
||||
// Parse the body
|
||||
// Construct the body
|
||||
WBXMLDocument doc = new WBXMLDocument();
|
||||
doc.LoadXml(request.Body);
|
||||
doc.VersionNumber = 1.3;
|
||||
@ -291,8 +291,11 @@ namespace Acacia.ZPush.Connect
|
||||
|
||||
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");
|
||||
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)
|
||||
{
|
||||
return new Response(response);
|
||||
|
@ -46,14 +46,14 @@ namespace Acacia.ZPush.Connect
|
||||
public ResponseType Execute<ResponseType>(SoapRequest<ResponseType> request)
|
||||
{
|
||||
// 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,
|
||||
// TODO: this username is a bit of a quick hack.
|
||||
request.UserName ?? _connection.Account.UserName,
|
||||
request.UserName ?? _connection.Account.Account.UserName,
|
||||
"webservice");
|
||||
|
||||
// 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;
|
||||
|
||||
// Execute the request
|
||||
@ -85,7 +85,7 @@ namespace Acacia.ZPush.Connect
|
||||
get
|
||||
{
|
||||
SoapParameters parameters = new SoapParameters();
|
||||
parameters.Add("devid", _connection.Account.DeviceId.ToLower());
|
||||
parameters.Add("devid", _connection.Account.Account.DeviceId.ToLower());
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
using Acacia.Features;
|
||||
using Acacia.Stubs;
|
||||
using Microsoft.Office.Interop.Outlook;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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