mirror of
https://github.com/Kopano-dev/kopano-ol-extension.git
synced 2023-10-10 13:37:40 +02:00
Partial implementation of raw MAPI access.
This commit is contained in:
parent
d1eaaba84e
commit
f5ea05189c
@ -276,9 +276,15 @@
|
||||
<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="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="OutlookConstants.cs" />
|
||||
<Compile Include="SearchQuery.cs" />
|
||||
<Compile Include="Stubs\Enums.cs" />
|
||||
<Compile Include="Stubs\IAccount.cs" />
|
||||
<Compile Include="Stubs\IAddIn.cs" />
|
||||
|
@ -1,486 +0,0 @@
|
||||
/// 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);
|
||||
} */
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
135
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs
Normal file
135
src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs
Normal file
@ -0,0 +1,135 @@
|
||||
/// 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 SearchQuery.PropertyIdentifier.FromTag(prop, (ushort)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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,331 @@
|
||||
|
||||
using Acacia.Stubs;
|
||||
/// 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 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;
|
||||
}
|
||||
|
||||
public SearchQuery ToSearchQuery()
|
||||
{
|
||||
return new SearchQuery.PropertyCompare(ulPropTag.ToPropertyIdentifier(),
|
||||
(SearchQuery.ComparisonOperation)(int)relop,
|
||||
prop->ToObject());
|
||||
}
|
||||
}
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
public SearchQuery ToSearchQuery()
|
||||
{
|
||||
return new SearchQuery.PropertyContent(ulPropTag.ToPropertyIdentifier(),
|
||||
(uint)fuzzy, // TODO
|
||||
prop->ToObject());
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
public uint dwReserved;
|
||||
public SRestriction* ptr;
|
||||
|
||||
public string ToString(int depth)
|
||||
{
|
||||
return ptr->ToString(depth);
|
||||
}
|
||||
|
||||
public SearchQuery ToSearchQuery()
|
||||
{
|
||||
return new SearchQuery.Not(ptr->ToSearchQuery());
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
public SearchQuery ToSearchQuery()
|
||||
{
|
||||
return new SearchQuery.PropertyBitMask(prop.ToPropertyIdentifier(), bmr == BMR.EQZ, mask);
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
public SearchQuery ToSearchQuery()
|
||||
{
|
||||
return new SearchQuery.PropertyExists(prop.ToPropertyIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
unsafe public struct SRestriction
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public RestrictionType rt;
|
||||
|
||||
// And/Or
|
||||
[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 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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
} */
|
||||
}
|
278
src/AcaciaZPushPlugin/AcaciaZPushPlugin/SearchQuery.cs
Normal file
278
src/AcaciaZPushPlugin/AcaciaZPushPlugin/SearchQuery.cs
Normal file
@ -0,0 +1,278 @@
|
||||
/// 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);
|
||||
}
|
||||
|
||||
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(part, "AND");
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.Or part)
|
||||
{
|
||||
EncodeMulti(part, "OR");
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.Not part)
|
||||
{
|
||||
_builder.Append("NOT ");
|
||||
part.Operand.Encode(this);
|
||||
}
|
||||
|
||||
private void EncodeMulti(SearchQuery.MultiOperator part, string oper)
|
||||
{
|
||||
Indent();
|
||||
_builder.Append(oper).Append("\n");
|
||||
Indent();
|
||||
_builder.Append("{\n");
|
||||
|
||||
++_indent;
|
||||
|
||||
foreach (SearchQuery operand in part.Operands)
|
||||
operand.Encode(this);
|
||||
|
||||
--_indent;
|
||||
|
||||
Indent();
|
||||
_builder.Append("}\n");
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.PropertyBitMask part)
|
||||
{
|
||||
_builder.Append("BITMASK:").Append(part.Property); // TODO: operator/value
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.PropertyCompare part)
|
||||
{
|
||||
_builder.Append("COMPARE:").Append(part.Property); // TODO: operator/value
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.PropertyContent part)
|
||||
{
|
||||
_builder.Append("CONTENT:").Append(part.Property); // TODO: operator/value
|
||||
}
|
||||
|
||||
public void Encode(SearchQuery.PropertyExists part)
|
||||
{
|
||||
_builder.Append("EXISTS:").Append(part.Property);
|
||||
}
|
||||
|
||||
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 IEnumerable<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
|
||||
{
|
||||
private string _id;
|
||||
|
||||
public PropertyIdentifier(string id)
|
||||
{
|
||||
this._id = id;
|
||||
}
|
||||
|
||||
public static PropertyIdentifier FromTag(ushort prop, ushort type)
|
||||
{
|
||||
return new PropertyIdentifier(string.Format("{0:4X}{1:4X}", prop, type));
|
||||
}
|
||||
}
|
||||
|
||||
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 class PropertyContent : PropertyQuery
|
||||
{
|
||||
public PropertyContent(PropertyIdentifier property, uint options, object content) : base(property)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
public override void Encode(ISearchEncoder encoder)
|
||||
{
|
||||
encoder.Encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class PropertyBitMask : PropertyQuery
|
||||
{
|
||||
public PropertyBitMask(PropertyIdentifier property, bool wantZero, uint mask) : base(property)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
public override void Encode(ISearchEncoder encoder)
|
||||
{
|
||||
encoder.Encode(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -62,6 +62,13 @@ namespace Acacia.Stubs
|
||||
SuggestedContacts = 30
|
||||
}
|
||||
|
||||
// Replacement for OlSpecialFolders
|
||||
public enum SpecialFolder
|
||||
{
|
||||
AllTasks = 0,
|
||||
Reminders = 1
|
||||
}
|
||||
|
||||
public enum AccountType
|
||||
{
|
||||
// TODO
|
||||
|
@ -114,5 +114,11 @@ namespace Acacia.Stubs
|
||||
ZPushFolder ZPush { get; set; }
|
||||
|
||||
IFolder Clone();
|
||||
|
||||
SearchQuery SearchCriteria
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,10 +53,14 @@ namespace Acacia.Stubs
|
||||
ISearchField AddField(string name, bool isUserField = false);
|
||||
}
|
||||
|
||||
public interface ISearch<ItemType> : ISearchOperator, IDisposable
|
||||
where ItemType : IItem
|
||||
public interface ISearchQuery : ISearchOperator
|
||||
{
|
||||
ISearchOperator AddOperator(SearchOperator oper);
|
||||
}
|
||||
|
||||
public interface ISearch<ItemType> : ISearchQuery, IDisposable
|
||||
where ItemType : IItem
|
||||
{
|
||||
|
||||
IEnumerable<ItemType> Search(int maxResults = int.MaxValue);
|
||||
|
||||
|
@ -40,6 +40,12 @@ namespace Acacia.Stubs
|
||||
/// </summary>
|
||||
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);
|
||||
string DisplayName { get; }
|
||||
string StoreID { get; }
|
||||
|
@ -23,6 +23,7 @@ using System.Collections;
|
||||
using Acacia.Utils;
|
||||
using Acacia.ZPush;
|
||||
using NSOutlook = Microsoft.Office.Interop.Outlook;
|
||||
using Acacia.Native.MAPI;
|
||||
|
||||
namespace Acacia.Stubs.OutlookWrappers
|
||||
{
|
||||
@ -371,5 +372,31 @@ namespace Acacia.Stubs.OutlookWrappers
|
||||
get;
|
||||
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)
|
||||
{
|
||||
using (ComRelease com = new ComRelease())
|
||||
|
Loading…
x
Reference in New Issue
Block a user