mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Search criteria encoding
This commit is contained in:
parent
d1eaaba84e
commit
c5325b4623
@ -276,9 +276,16 @@
|
|||||||
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
|
||||||
<Compile Include="GlobalOptions.cs" />
|
<Compile Include="GlobalOptions.cs" />
|
||||||
<Compile Include="Logging.cs" />
|
<Compile Include="Logging.cs" />
|
||||||
<Compile Include="Native\MAPI.cs" />
|
|
||||||
<Compile Include="Native\IOleWindow.cs" />
|
<Compile Include="Native\IOleWindow.cs" />
|
||||||
|
<Compile Include="Native\MAPI\Binary.cs" />
|
||||||
|
<Compile Include="Native\MAPI\IMAPIContainer.cs" />
|
||||||
|
<Compile Include="Native\MAPI\IMAPIFolder.cs" />
|
||||||
|
<Compile Include="Native\MAPI\IMAPIProp.cs" />
|
||||||
|
<Compile Include="Native\MAPI\Property.cs" />
|
||||||
|
<Compile Include="Native\MAPI\Restriction.cs" />
|
||||||
|
<Compile Include="Native\NativeEncoder.cs" />
|
||||||
<Compile Include="OutlookConstants.cs" />
|
<Compile Include="OutlookConstants.cs" />
|
||||||
|
<Compile Include="SearchQuery.cs" />
|
||||||
<Compile Include="Stubs\Enums.cs" />
|
<Compile Include="Stubs\Enums.cs" />
|
||||||
<Compile Include="Stubs\IAccount.cs" />
|
<Compile Include="Stubs\IAccount.cs" />
|
||||||
<Compile Include="Stubs\IAddIn.cs" />
|
<Compile Include="Stubs\IAddIn.cs" />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
using Acacia.Native.MAPI;
|
using Acacia.Native.MAPI;
|
||||||
|
using Acacia.Stubs;
|
||||||
/// Copyright 2016 Kopano b.v.
|
/// Copyright 2016 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// This program is free software: you can redistribute it and/or modify
|
||||||
@ -80,13 +81,21 @@ namespace Acacia.Features.WebApp
|
|||||||
if (account == null)
|
if (account == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
using (IFolder reminders = account.Account.Store.GetSpecialFolder(SpecialFolder.Reminders))
|
||||||
|
{
|
||||||
|
Logger.Instance.Trace(this, "REMINDERS:\n{0}", reminders.SearchCriteria);
|
||||||
|
using (RestrictionEncoder res = reminders.SearchCriteria.ToRestriction())
|
||||||
|
Logger.Instance.Trace(this, "REMINDERS2:\n{0}", res.Restriction);
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
// Get the url
|
// Get the url
|
||||||
string url = AutoDiscover(account);
|
string url = AutoDiscover(account);
|
||||||
if (url == null)
|
if (url == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Open the browser
|
// Open the browser
|
||||||
System.Diagnostics.Process.Start(url);
|
System.Diagnostics.Process.Start(url);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private string AutoDiscover(ZPushAccount account)
|
private string AutoDiscover(ZPushAccount account)
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
using Acacia.Utils;
|
||||||
|
/// 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.MAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/// 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.MAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SearchCriteriaState : UInt32
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
SEARCH_RUNNING = 1,
|
||||||
|
SEARCH_REBUILD = 2,
|
||||||
|
SEARCH_RECURSIVE = 4,
|
||||||
|
SEARCH_FOREGROUND = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum SearchCriteriaFlags : 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 : IMAPIProp
|
||||||
|
{
|
||||||
|
// IMAPIProp
|
||||||
|
new void GetLastError(Int32 hResult, UInt32 flags, out IntPtr ptr);
|
||||||
|
new void SaveChanges(SaveChangesFlags flags);
|
||||||
|
new void GetProps();
|
||||||
|
new void GetPropList();
|
||||||
|
new void OpenProperty();
|
||||||
|
new void SetProps();
|
||||||
|
new void DeleteProps();
|
||||||
|
new void CopyTo();
|
||||||
|
new void CopyProps();
|
||||||
|
new void GetNamesFromIDs();
|
||||||
|
new void GetIDsFromNames();
|
||||||
|
|
||||||
|
// IMAPIContainer
|
||||||
|
void GetContentsTable(UInt32 flags, out IntPtr table);
|
||||||
|
void GetHierarchyTable();
|
||||||
|
void OpenEntry();
|
||||||
|
void SetSearchCriteria(SRestriction* lppRestriction, SBinaryArray* lppContainerList, SearchCriteriaFlags flags);
|
||||||
|
void GetSearchCriteria(UInt32 flags, SRestriction** lppRestriction, SBinaryArray** lppContainerList, out SearchCriteriaState state);
|
||||||
|
}
|
||||||
|
}
|
@ -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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Acacia.Native.MAPI
|
||||||
|
{
|
||||||
|
[ComImport]
|
||||||
|
[Guid("0002030C-0000-0000-C000-000000000046")]
|
||||||
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
unsafe public interface IMAPIFolder : IMAPIContainer
|
||||||
|
{
|
||||||
|
// IMAPIProp
|
||||||
|
new void GetLastError(Int32 hResult, UInt32 flags, out IntPtr ptr);
|
||||||
|
new void SaveChanges(SaveChangesFlags flags);
|
||||||
|
new void GetProps();
|
||||||
|
new void GetPropList();
|
||||||
|
new void OpenProperty();
|
||||||
|
new void SetProps();
|
||||||
|
new void DeleteProps();
|
||||||
|
new void CopyTo();
|
||||||
|
new void CopyProps();
|
||||||
|
new void GetNamesFromIDs();
|
||||||
|
new void GetIDsFromNames();
|
||||||
|
|
||||||
|
// IMAPIContainer
|
||||||
|
new void GetContentsTable(UInt32 flags, out IntPtr table);
|
||||||
|
new void GetHierarchyTable();
|
||||||
|
new void OpenEntry();
|
||||||
|
new void SetSearchCriteria(SRestriction* lppRestriction, SBinaryArray* lppContainerList, SearchCriteriaFlags flags);
|
||||||
|
new void GetSearchCriteria(UInt32 flags, SRestriction** lppRestriction, SBinaryArray** lppContainerList, out SearchCriteriaState state);
|
||||||
|
|
||||||
|
// IMAPIFolder
|
||||||
|
void CreateMessage();
|
||||||
|
void CopyMessages();
|
||||||
|
void DeleteMessages();
|
||||||
|
void CreateFolder();
|
||||||
|
void CopyFolder();
|
||||||
|
void DeleteFolder();
|
||||||
|
void SetReadFlags();
|
||||||
|
void GetMessageStatus();
|
||||||
|
void SetMessageStatus();
|
||||||
|
void SaveContentsSort();
|
||||||
|
void EmptyFolder();
|
||||||
|
}
|
||||||
|
}
|
@ -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.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();
|
||||||
|
}
|
||||||
|
}
|
140
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs
Normal file
140
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/// 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.MAPI
|
||||||
|
{
|
||||||
|
|
||||||
|
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 + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchQuery.PropertyIdentifier ToPropertyIdentifier()
|
||||||
|
{
|
||||||
|
return new SearchQuery.PropertyIdentifier(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[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()
|
||||||
|
{
|
||||||
|
return ToObject()?.ToString() ?? "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ToObject()
|
||||||
|
{
|
||||||
|
switch (ulPropTag.type)
|
||||||
|
{
|
||||||
|
case PropType.BOOLEAN:
|
||||||
|
return b;
|
||||||
|
case PropType.STRING8:
|
||||||
|
return new string(lpszA);
|
||||||
|
case PropType.BINARY:
|
||||||
|
return bin;
|
||||||
|
//case PropType.UNICODE:
|
||||||
|
// return lpszW.ToString();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropValue* FromObject(NativeEncoder encoder, object value)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
/// Copyright 2017 Kopano b.v.
|
|
||||||
|
using Acacia.Stubs;
|
||||||
|
using Acacia.Utils;
|
||||||
|
/// Copyright 2017 Kopano b.v.
|
||||||
///
|
///
|
||||||
/// This program is free software: you can redistribute it and/or modify
|
/// This program is free software: you can redistribute it and/or modify
|
||||||
/// it under the terms of the GNU Affero General Public License, version 3,
|
/// it under the terms of the GNU Affero General Public License, version 3,
|
||||||
@ -13,8 +16,6 @@
|
|||||||
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
/// along with this program.If not, see<http://www.gnu.org/licenses/>.
|
||||||
///
|
///
|
||||||
/// Consult LICENSE file for details
|
/// Consult LICENSE file for details
|
||||||
|
|
||||||
using Acacia.Utils;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -24,167 +25,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Acacia.Native.MAPI
|
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
|
unsafe public struct CommentRestriction
|
||||||
{
|
{
|
||||||
@ -207,6 +47,13 @@ namespace Acacia.Native.MAPI
|
|||||||
s += "\n";
|
s += "\n";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
return new SearchQuery.PropertyCompare(ulPropTag.ToPropertyIdentifier(),
|
||||||
|
(SearchQuery.ComparisonOperation)(int)relop,
|
||||||
|
prop->ToObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
@ -223,18 +70,26 @@ namespace Acacia.Native.MAPI
|
|||||||
|
|
||||||
unsafe public struct ContentRestriction
|
unsafe public struct ContentRestriction
|
||||||
{
|
{
|
||||||
public FuzzyLevel fuzzy;
|
public FuzzyLevel ulFuzzyLevel;
|
||||||
public PropTag ulPropTag;
|
public PropTag ulPropTag;
|
||||||
public PropValue* prop;
|
public PropValue* prop;
|
||||||
|
|
||||||
public string ToString(int depth)
|
public string ToString(int depth)
|
||||||
{
|
{
|
||||||
string indent = new string(' ', depth);
|
string indent = new string(' ', depth);
|
||||||
string s = indent + fuzzy + ":" + ulPropTag.ToString();
|
string s = indent + ulFuzzyLevel + ":" + ulPropTag.ToString();
|
||||||
s += ":" + prop->ToString();
|
s += ":" + prop->ToString();
|
||||||
s += "\n";
|
s += "\n";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
return new SearchQuery.PropertyContent(ulPropTag.ToPropertyIdentifier(),
|
||||||
|
(SearchQuery.ContentMatchOperation)((uint)ulFuzzyLevel & 0xF),
|
||||||
|
(SearchQuery.ContentMatchModifiers)(((uint)ulFuzzyLevel & 0xF0000) >> 16),
|
||||||
|
prop->ToObject());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: merge with ISearch
|
// TODO: merge with ISearch
|
||||||
@ -269,6 +124,16 @@ namespace Acacia.Native.MAPI
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery(bool and)
|
||||||
|
{
|
||||||
|
SearchQuery.MultiOperator oper = and ? (SearchQuery.MultiOperator)new SearchQuery.And() : new SearchQuery.Or(); ;
|
||||||
|
for (uint i = 0; i < cb; ++i)
|
||||||
|
{
|
||||||
|
oper.Add(ptr[i].ToSearchQuery());
|
||||||
|
}
|
||||||
|
return oper;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe public struct NotRestriction
|
unsafe public struct NotRestriction
|
||||||
@ -280,6 +145,11 @@ namespace Acacia.Native.MAPI
|
|||||||
{
|
{
|
||||||
return ptr->ToString(depth);
|
return ptr->ToString(depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
return new SearchQuery.Not(ptr->ToSearchQuery());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BMR : uint
|
public enum BMR : uint
|
||||||
@ -303,6 +173,11 @@ namespace Acacia.Native.MAPI
|
|||||||
string indent = new string(' ', depth);
|
string indent = new string(' ', depth);
|
||||||
return indent + ToString() + "\n";
|
return indent + ToString() + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
return new SearchQuery.PropertyBitMask(prop.ToPropertyIdentifier(), (SearchQuery.BitMaskOperation)(int)bmr, mask);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe public struct ExistRestriction
|
unsafe public struct ExistRestriction
|
||||||
@ -320,6 +195,11 @@ namespace Acacia.Native.MAPI
|
|||||||
string indent = new string(' ', depth);
|
string indent = new string(' ', depth);
|
||||||
return indent + prop.ToString() + "\n";
|
return indent + prop.ToString() + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
return new SearchQuery.PropertyExists(prop.ToPropertyIdentifier());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
@ -328,6 +208,7 @@ namespace Acacia.Native.MAPI
|
|||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public RestrictionType rt;
|
public RestrictionType rt;
|
||||||
|
|
||||||
|
// And/Or
|
||||||
[FieldOffset(8)]
|
[FieldOffset(8)]
|
||||||
public SubRestriction sub;
|
public SubRestriction sub;
|
||||||
|
|
||||||
@ -349,6 +230,37 @@ namespace Acacia.Native.MAPI
|
|||||||
[FieldOffset(8)]
|
[FieldOffset(8)]
|
||||||
public CommentRestriction comment;
|
public CommentRestriction comment;
|
||||||
|
|
||||||
|
public SearchQuery ToSearchQuery()
|
||||||
|
{
|
||||||
|
switch (rt)
|
||||||
|
{
|
||||||
|
case RestrictionType.AND:
|
||||||
|
return sub.ToSearchQuery(true);
|
||||||
|
case RestrictionType.OR:
|
||||||
|
return sub.ToSearchQuery(false);
|
||||||
|
case RestrictionType.NOT:
|
||||||
|
return not.ToSearchQuery();
|
||||||
|
case RestrictionType.CONTENT:
|
||||||
|
return content.ToSearchQuery();
|
||||||
|
case RestrictionType.PROPERTY:
|
||||||
|
return prop.ToSearchQuery();
|
||||||
|
case RestrictionType.BITMASK:
|
||||||
|
return bitMask.ToSearchQuery();
|
||||||
|
case RestrictionType.EXIST:
|
||||||
|
return exist.ToSearchQuery();
|
||||||
|
|
||||||
|
/* TODO COMPAREPROPS,
|
||||||
|
BITMASK,
|
||||||
|
SIZE,
|
||||||
|
SUBRESTRICTION,
|
||||||
|
COMMENT,
|
||||||
|
COUNT,
|
||||||
|
ANNOTATION*/
|
||||||
|
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return ToString(0);
|
return ToString(0);
|
||||||
@ -358,7 +270,7 @@ namespace Acacia.Native.MAPI
|
|||||||
{
|
{
|
||||||
string indent = new string(' ', depth);
|
string indent = new string(' ', depth);
|
||||||
string s = indent + rt.ToString() + "\n" + indent + "{\n";
|
string s = indent + rt.ToString() + "\n" + indent + "{\n";
|
||||||
switch(rt)
|
switch (rt)
|
||||||
{
|
{
|
||||||
case RestrictionType.AND:
|
case RestrictionType.AND:
|
||||||
case RestrictionType.OR:
|
case RestrictionType.OR:
|
||||||
@ -394,69 +306,143 @@ namespace Acacia.Native.MAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
/// <summary>
|
||||||
public enum GetSearchCriteriaState : UInt32
|
/// Encodes a search as an SRestriction. Note that as memory needs to be managed for the miscellaneous structures,
|
||||||
|
/// the SRestriction is only valid until RestrictionEncoder is disposed.
|
||||||
|
/// </summary>
|
||||||
|
unsafe public class RestrictionEncoder : NativeEncoder, ISearchEncoder
|
||||||
{
|
{
|
||||||
NONE = 0,
|
private class EncodingStack
|
||||||
SEARCH_RUNNING = 1,
|
{
|
||||||
SEARCH_REBUILD = 2,
|
public SRestriction[] array;
|
||||||
SEARCH_RECURSIVE = 4,
|
public int index;
|
||||||
SEARCH_FOREGROUND = 8
|
public SRestriction* ptr;
|
||||||
|
|
||||||
|
public EncodingStack(int count, Allocation<SRestriction[]> alloc)
|
||||||
|
{
|
||||||
|
array = alloc.Object;
|
||||||
|
index = 0;
|
||||||
|
ptr = (SRestriction*)alloc.Pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private readonly Stack<EncodingStack> _current = new Stack<EncodingStack>();
|
||||||
|
private readonly EncodingStack _root;
|
||||||
|
|
||||||
|
public RestrictionEncoder()
|
||||||
|
{
|
||||||
|
// Create an object for the root element
|
||||||
|
_root = Begin(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DoRelease()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public SRestriction Restriction
|
||||||
|
{
|
||||||
|
get { return _root.array[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private SRestriction* Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
EncodingStack top = _current.Peek();
|
||||||
|
return top.ptr + top.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyExists part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.Or part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyIdentifier part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.Not part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.And part)
|
||||||
|
{
|
||||||
|
Current->rt = RestrictionType.AND;
|
||||||
|
Current->sub.cb = (uint)part.Operands.Count;
|
||||||
|
Current->sub.ptr = EncodePointer(part.Operands);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SRestriction* EncodePointer(IEnumerable<SearchQuery> operands)
|
||||||
|
{
|
||||||
|
EncodingStack alloc = Begin(operands.Count());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (SearchQuery operand in operands)
|
||||||
|
{
|
||||||
|
operand.Encode(this);
|
||||||
|
++alloc.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
return alloc.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EncodingStack Begin(int count)
|
||||||
|
{
|
||||||
|
// Allocate and push the array
|
||||||
|
EncodingStack alloc = new EncodingStack(count, Allocate(new SRestriction[count]));
|
||||||
|
_current.Push(alloc);
|
||||||
|
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void End()
|
||||||
|
{
|
||||||
|
_current.Pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyContent part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyCompare part)
|
||||||
|
{
|
||||||
|
Current->rt = RestrictionType.PROPERTY;
|
||||||
|
Current->prop.relop = (SearchOperation)part.Operation;
|
||||||
|
Current->prop.ulPropTag = part.Property.Tag;
|
||||||
|
Current->prop.prop = PropValue.FromObject(this, part.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyBitMask part)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
public static class RestrictionExensions
|
||||||
public enum SetSearchCriteriaFlags : UInt32
|
|
||||||
{
|
{
|
||||||
NONE = 0,
|
/// <summary>
|
||||||
STOP_SEARCH = 0x00000001,
|
/// Encodes the search as an SRestriction.
|
||||||
RESTART_SEARCH = 0x00000002,
|
/// </summary>
|
||||||
RECURSIVE_SEARCH = 0x00000004,
|
/// <returns>The encoder containing the restriction. The caller is responsible for disposing.</returns>
|
||||||
SHALLOW_SEARCH = 0x00000008,
|
public static RestrictionEncoder ToRestriction(this SearchQuery search)
|
||||||
FOREGROUND_SEARCH = 0x00000010,
|
{
|
||||||
BACKGROUND_SEARCH = 0x00000020,
|
RestrictionEncoder encoder = new RestrictionEncoder();
|
||||||
}
|
search.Encode(encoder);
|
||||||
|
return encoder;
|
||||||
[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
|
/* Example search code
|
@ -0,0 +1,82 @@
|
|||||||
|
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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper for encoding objects into native structures.
|
||||||
|
/// </summary>
|
||||||
|
abstract public class NativeEncoder : DisposableWrapper
|
||||||
|
{
|
||||||
|
abstract protected class AllocationBase
|
||||||
|
{
|
||||||
|
protected readonly object _obj;
|
||||||
|
protected readonly GCHandle _handle;
|
||||||
|
protected readonly IntPtr _ptr;
|
||||||
|
|
||||||
|
public AllocationBase(Type type, int size)
|
||||||
|
{
|
||||||
|
_ptr = Marshal.AllocHGlobal(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllocationBase(object obj)
|
||||||
|
{
|
||||||
|
this._obj = obj;
|
||||||
|
_handle = GCHandle.Alloc(obj, GCHandleType.Pinned);
|
||||||
|
_ptr = _handle.AddrOfPinnedObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: release
|
||||||
|
}
|
||||||
|
unsafe protected class Allocation<ObjType> : AllocationBase
|
||||||
|
{
|
||||||
|
public Allocation(int size) : base(typeof(ObjType), size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Allocation(ObjType obj) : base(obj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjType Object
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (ObjType)_obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPtr Pointer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<AllocationBase> _allocs = new List<AllocationBase>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates an object of the specified type. The allocation is managed by this encoder.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">If larger than 0, the size to allocate. Otherwise, the size of the object is used.</param>
|
||||||
|
/// <returns>The allocated object.</returns>
|
||||||
|
protected Allocation<ObjType> Allocate<ObjType>(int size = -1)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Allocation<ObjType> Allocate<ObjType>(ObjType obj)
|
||||||
|
{
|
||||||
|
Allocation<ObjType> alloc = new Allocation<ObjType>(obj);
|
||||||
|
_allocs.Add(alloc);
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
364
src/AcaciaZPushPlugin/AcaciaZPushPlugin/SearchQuery.cs
Normal file
364
src/AcaciaZPushPlugin/AcaciaZPushPlugin/SearchQuery.cs
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
/// 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 Acacia.Native.MAPI;
|
||||||
|
|
||||||
|
namespace Acacia
|
||||||
|
{
|
||||||
|
public interface ISearchEncoder
|
||||||
|
{
|
||||||
|
void Encode(SearchQuery.PropertyBitMask part);
|
||||||
|
void Encode(SearchQuery.PropertyCompare part);
|
||||||
|
void Encode(SearchQuery.PropertyContent part);
|
||||||
|
void Encode(SearchQuery.PropertyExists part);
|
||||||
|
void Encode(SearchQuery.And part);
|
||||||
|
void Encode(SearchQuery.Or part);
|
||||||
|
void Encode(SearchQuery.Not part);
|
||||||
|
void Encode(SearchQuery.PropertyIdentifier part);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ToStringEncoder : ISearchEncoder
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _builder = new StringBuilder();
|
||||||
|
private int _indent;
|
||||||
|
|
||||||
|
private void Indent()
|
||||||
|
{
|
||||||
|
_builder.Append(new String(' ', _indent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.And part)
|
||||||
|
{
|
||||||
|
EncodeMulti("AND", part.Operands);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.Or part)
|
||||||
|
{
|
||||||
|
EncodeMulti("OR", part.Operands);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.Not part)
|
||||||
|
{
|
||||||
|
EncodeMulti("NOT", new[] { part.Operand });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EncodeMulti(string oper, IEnumerable<SearchQuery> parts)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
_builder.Append(oper).Append("\n");
|
||||||
|
Indent();
|
||||||
|
_builder.Append("{\n");
|
||||||
|
|
||||||
|
++_indent;
|
||||||
|
|
||||||
|
foreach (SearchQuery operand in parts)
|
||||||
|
operand.Encode(this);
|
||||||
|
|
||||||
|
--_indent;
|
||||||
|
|
||||||
|
Indent();
|
||||||
|
_builder.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyBitMask part)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
_builder.Append("BITMASK{");
|
||||||
|
part.Property.Encode(this);
|
||||||
|
_builder.Append(" ").Append(part.Operation).Append(" ");
|
||||||
|
_builder.Append(part.Mask.ToString("X8"));
|
||||||
|
_builder.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string[] COMPARISON_OPERATORS = {"<", "<=", ">", ">=", "==", "!=", "LIKE"};
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyCompare part)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
_builder.Append("COMPARE{");
|
||||||
|
part.Property.Encode(this);
|
||||||
|
_builder.Append(" ").Append(COMPARISON_OPERATORS[(int)part.Operation]).Append(" ");
|
||||||
|
_builder.Append(part.Value);
|
||||||
|
_builder.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyContent part)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
_builder.Append("CONTENT{");
|
||||||
|
part.Property.Encode(this);
|
||||||
|
|
||||||
|
List<string> options = new List<string>();
|
||||||
|
if (part.Operation != SearchQuery.ContentMatchOperation.Full)
|
||||||
|
options.Add(part.Operation.ToString());
|
||||||
|
|
||||||
|
if (part.Modifiers != SearchQuery.ContentMatchModifiers.None)
|
||||||
|
{
|
||||||
|
options.Add(part.Modifiers.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
string optionsString = options.Count == 0 ? "" : ("(" + string.Join(",", options) + ")");
|
||||||
|
|
||||||
|
_builder.Append(" ==").Append(optionsString).Append(" ");
|
||||||
|
_builder.Append(part.Content);
|
||||||
|
_builder.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyExists part)
|
||||||
|
{
|
||||||
|
Indent();
|
||||||
|
_builder.Append("EXISTS{");
|
||||||
|
part.Property.Encode(this);
|
||||||
|
_builder.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(SearchQuery.PropertyIdentifier part)
|
||||||
|
{
|
||||||
|
_builder.Append(part.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue()
|
||||||
|
{
|
||||||
|
return _builder.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public class SearchQuery
|
||||||
|
{
|
||||||
|
#region Interface
|
||||||
|
|
||||||
|
override public string ToString()
|
||||||
|
{
|
||||||
|
ToStringEncoder encoder = new ToStringEncoder();
|
||||||
|
Encode(encoder);
|
||||||
|
return encoder.GetValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public void Encode(ISearchEncoder encoder);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Implementations
|
||||||
|
|
||||||
|
abstract public class MultiOperator : SearchQuery
|
||||||
|
{
|
||||||
|
private readonly List<SearchQuery> _operands = new List<SearchQuery>();
|
||||||
|
|
||||||
|
public void Add(SearchQuery operand)
|
||||||
|
{
|
||||||
|
if (operand == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
_operands.Add(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<SearchQuery> Operands
|
||||||
|
{
|
||||||
|
get { return _operands; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class And : MultiOperator
|
||||||
|
{
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Or : MultiOperator
|
||||||
|
{
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Not : SearchQuery
|
||||||
|
{
|
||||||
|
public SearchQuery Operand
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Not(SearchQuery operand)
|
||||||
|
{
|
||||||
|
this.Operand = operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TODO: this is globally useful
|
||||||
|
/// </summary>
|
||||||
|
public class PropertyIdentifier
|
||||||
|
{
|
||||||
|
public string Id { get; private set; }
|
||||||
|
public PropTag Tag { get; private set; }
|
||||||
|
|
||||||
|
public PropertyIdentifier(PropTag tag)
|
||||||
|
{
|
||||||
|
this.Tag = tag;
|
||||||
|
Id = string.Format("{0:X4}{1:X4}", tag.prop, (int)tag.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public class PropertyQuery : SearchQuery
|
||||||
|
{
|
||||||
|
public PropertyIdentifier Property { get; set; }
|
||||||
|
|
||||||
|
protected PropertyQuery(PropertyIdentifier property)
|
||||||
|
{
|
||||||
|
this.Property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order matches MAPI RELOP_ constants
|
||||||
|
/// </summary>
|
||||||
|
public enum ComparisonOperation : uint
|
||||||
|
{
|
||||||
|
Smaller,
|
||||||
|
SmallerEqual,
|
||||||
|
Greater,
|
||||||
|
GreaterEqual,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
Like
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyCompare : PropertyQuery
|
||||||
|
{
|
||||||
|
public ComparisonOperation Operation { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
|
||||||
|
public PropertyCompare(PropertyIdentifier property, ComparisonOperation operation, object value) : base(property)
|
||||||
|
{
|
||||||
|
this.Operation = operation;
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyExists : PropertyQuery
|
||||||
|
{
|
||||||
|
public PropertyExists(PropertyIdentifier property) : base(property)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ContentMatchOperation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Match full content
|
||||||
|
/// </summary>
|
||||||
|
Full,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Match part of the content
|
||||||
|
/// </summary>
|
||||||
|
SubString,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Match the start of the content
|
||||||
|
/// </summary>
|
||||||
|
Prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ContentMatchModifiers
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
CaseInsensitive = 1,
|
||||||
|
IgnoreNonSpace = 2,
|
||||||
|
Loose = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyContent : PropertyQuery
|
||||||
|
{
|
||||||
|
public ContentMatchOperation Operation { get; set; }
|
||||||
|
public ContentMatchModifiers Modifiers { get; set; }
|
||||||
|
public object Content { get; set; }
|
||||||
|
|
||||||
|
public PropertyContent(PropertyIdentifier property, ContentMatchOperation operation, ContentMatchModifiers modifiers, object content) : base(property)
|
||||||
|
{
|
||||||
|
this.Operation = operation;
|
||||||
|
this.Modifiers = modifiers;
|
||||||
|
this.Content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BitMaskOperation
|
||||||
|
{
|
||||||
|
EQZ, NEZ
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PropertyBitMask : PropertyQuery
|
||||||
|
{
|
||||||
|
public BitMaskOperation Operation { get; set; }
|
||||||
|
public uint Mask { get; set; }
|
||||||
|
|
||||||
|
public PropertyBitMask(PropertyIdentifier property, BitMaskOperation operation, uint mask) : base(property)
|
||||||
|
{
|
||||||
|
this.Operation = operation;
|
||||||
|
this.Mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Encode(ISearchEncoder encoder)
|
||||||
|
{
|
||||||
|
encoder.Encode(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -62,6 +62,13 @@ namespace Acacia.Stubs
|
|||||||
SuggestedContacts = 30
|
SuggestedContacts = 30
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replacement for OlSpecialFolders
|
||||||
|
public enum SpecialFolder
|
||||||
|
{
|
||||||
|
AllTasks = 0,
|
||||||
|
Reminders = 1
|
||||||
|
}
|
||||||
|
|
||||||
public enum AccountType
|
public enum AccountType
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -114,5 +114,11 @@ namespace Acacia.Stubs
|
|||||||
ZPushFolder ZPush { get; set; }
|
ZPushFolder ZPush { get; set; }
|
||||||
|
|
||||||
IFolder Clone();
|
IFolder Clone();
|
||||||
|
|
||||||
|
SearchQuery SearchCriteria
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,14 @@ namespace Acacia.Stubs
|
|||||||
ISearchField AddField(string name, bool isUserField = false);
|
ISearchField AddField(string name, bool isUserField = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISearch<ItemType> : ISearchOperator, IDisposable
|
public interface ISearchQuery : ISearchOperator
|
||||||
where ItemType : IItem
|
|
||||||
{
|
{
|
||||||
ISearchOperator AddOperator(SearchOperator oper);
|
ISearchOperator AddOperator(SearchOperator oper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISearch<ItemType> : ISearchQuery, IDisposable
|
||||||
|
where ItemType : IItem
|
||||||
|
{
|
||||||
|
|
||||||
IEnumerable<ItemType> Search(int maxResults = int.MaxValue);
|
IEnumerable<ItemType> Search(int maxResults = int.MaxValue);
|
||||||
|
|
||||||
|
@ -40,6 +40,12 @@ namespace Acacia.Stubs
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string GetDefaultFolderId(DefaultFolder folder);
|
string GetDefaultFolderId(DefaultFolder folder);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a special folder.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The special folder. The caller is responsible for disposing.</returns>
|
||||||
|
IFolder GetSpecialFolder(SpecialFolder folder);
|
||||||
|
|
||||||
IItem GetItemFromID(string id);
|
IItem GetItemFromID(string id);
|
||||||
string DisplayName { get; }
|
string DisplayName { get; }
|
||||||
string StoreID { get; }
|
string StoreID { get; }
|
||||||
|
@ -23,6 +23,7 @@ using System.Collections;
|
|||||||
using Acacia.Utils;
|
using Acacia.Utils;
|
||||||
using Acacia.ZPush;
|
using Acacia.ZPush;
|
||||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||||
|
using Acacia.Native.MAPI;
|
||||||
|
|
||||||
namespace Acacia.Stubs.OutlookWrappers
|
namespace Acacia.Stubs.OutlookWrappers
|
||||||
{
|
{
|
||||||
@ -371,5 +372,31 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe public SearchQuery SearchCriteria
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IMAPIFolder imapi = _item.MAPIOBJECT as IMAPIFolder;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SearchCriteriaState state;
|
||||||
|
SBinaryArray* sb1;
|
||||||
|
SRestriction* restrict;
|
||||||
|
imapi.GetSearchCriteria(0, &restrict, &sb1, out state);
|
||||||
|
Logger.Instance.Warning(this, "SEARCH:\n{0}", restrict->ToString());
|
||||||
|
return restrict->ToSearchQuery();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ComRelease.Release(imapi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,18 @@ namespace Acacia.Stubs.OutlookWrappers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IFolder GetSpecialFolder(SpecialFolder folder)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _item.GetSpecialFolder((NSOutlook.OlSpecialFolders)(int)folder).Wrap();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IItem GetItemFromID(string id)
|
public IItem GetItemFromID(string id)
|
||||||
{
|
{
|
||||||
using (ComRelease com = new ComRelease())
|
using (ComRelease com = new ComRelease())
|
||||||
|
Loading…
Reference in New Issue
Block a user