mirror of
				https://github.com/Kopano-dev/kopano-ol-extension.git
				synced 2023-10-10 11:37:40 +00:00 
			
		
		
		
	Search criteria encoding
This commit is contained in:
		| @@ -276,9 +276,16 @@ | ||||
|     <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="Native\NativeEncoder.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,5 +1,6 @@ | ||||
|  | ||||
| using Acacia.Native.MAPI; | ||||
| using Acacia.Stubs; | ||||
| /// Copyright 2016 Kopano b.v. | ||||
| ///  | ||||
| /// This program is free software: you can redistribute it and/or modify | ||||
| @@ -80,13 +81,21 @@ namespace Acacia.Features.WebApp | ||||
|             if (account == null) | ||||
|                 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 | ||||
|             string url = AutoDiscover(account); | ||||
|             if (url == null) | ||||
|                 return; | ||||
|  | ||||
|             // Open the browser | ||||
|             System.Diagnostics.Process.Start(url); | ||||
|             System.Diagnostics.Process.Start(url);*/ | ||||
|         } | ||||
|  | ||||
|         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 | ||||
| /// 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/>. | ||||
| ///  | ||||
| /// Consult LICENSE file for details | ||||
| 
 | ||||
| using Acacia.Utils; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| @@ -24,167 +25,6 @@ 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 | ||||
|     { | ||||
| @@ -207,6 +47,13 @@ namespace Acacia.Native.MAPI | ||||
|             s += "\n"; | ||||
|             return s; | ||||
|         } | ||||
| 
 | ||||
|         public SearchQuery ToSearchQuery() | ||||
|         { | ||||
|             return new SearchQuery.PropertyCompare(ulPropTag.ToPropertyIdentifier(), | ||||
|                 (SearchQuery.ComparisonOperation)(int)relop, | ||||
|                 prop->ToObject()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [Flags] | ||||
| @@ -223,18 +70,26 @@ namespace Acacia.Native.MAPI | ||||
| 
 | ||||
|     unsafe public struct ContentRestriction | ||||
|     { | ||||
|         public FuzzyLevel fuzzy; | ||||
|         public FuzzyLevel ulFuzzyLevel; | ||||
|         public PropTag ulPropTag; | ||||
|         public PropValue* prop; | ||||
| 
 | ||||
|         public string ToString(int depth) | ||||
|         { | ||||
|             string indent = new string(' ', depth); | ||||
|             string s = indent + fuzzy + ":" + ulPropTag.ToString(); | ||||
|             string s = indent + ulFuzzyLevel + ":" + ulPropTag.ToString(); | ||||
|             s += ":" + prop->ToString(); | ||||
|             s += "\n"; | ||||
|             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 | ||||
| @@ -269,6 +124,16 @@ namespace Acacia.Native.MAPI | ||||
|             } | ||||
|             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 | ||||
| @@ -280,6 +145,11 @@ namespace Acacia.Native.MAPI | ||||
|         { | ||||
|             return ptr->ToString(depth); | ||||
|         } | ||||
| 
 | ||||
|         public SearchQuery ToSearchQuery() | ||||
|         { | ||||
|             return new SearchQuery.Not(ptr->ToSearchQuery()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public enum BMR : uint | ||||
| @@ -303,6 +173,11 @@ namespace Acacia.Native.MAPI | ||||
|             string indent = new string(' ', depth); | ||||
|             return indent + ToString() + "\n"; | ||||
|         } | ||||
| 
 | ||||
|         public SearchQuery ToSearchQuery() | ||||
|         { | ||||
|             return new SearchQuery.PropertyBitMask(prop.ToPropertyIdentifier(), (SearchQuery.BitMaskOperation)(int)bmr, mask); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     unsafe public struct ExistRestriction | ||||
| @@ -320,6 +195,11 @@ namespace Acacia.Native.MAPI | ||||
|             string indent = new string(' ', depth); | ||||
|             return indent + prop.ToString() + "\n"; | ||||
|         } | ||||
| 
 | ||||
|         public SearchQuery ToSearchQuery() | ||||
|         { | ||||
|             return new SearchQuery.PropertyExists(prop.ToPropertyIdentifier()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [StructLayout(LayoutKind.Explicit)] | ||||
| @@ -328,6 +208,7 @@ namespace Acacia.Native.MAPI | ||||
|         [FieldOffset(0)] | ||||
|         public RestrictionType rt; | ||||
| 
 | ||||
|         // And/Or | ||||
|         [FieldOffset(8)] | ||||
|         public SubRestriction sub; | ||||
| 
 | ||||
| @@ -349,6 +230,37 @@ namespace Acacia.Native.MAPI | ||||
|         [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); | ||||
| @@ -358,7 +270,7 @@ namespace Acacia.Native.MAPI | ||||
|         { | ||||
|             string indent = new string(' ', depth); | ||||
|             string s = indent + rt.ToString() + "\n" + indent + "{\n"; | ||||
|             switch(rt) | ||||
|             switch (rt) | ||||
|             { | ||||
|                 case RestrictionType.AND: | ||||
|                 case RestrictionType.OR: | ||||
| @@ -394,69 +306,143 @@ namespace Acacia.Native.MAPI | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     [Flags] | ||||
|     public enum GetSearchCriteriaState : UInt32 | ||||
|     /// <summary> | ||||
|     /// 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, | ||||
|         SEARCH_RUNNING = 1, | ||||
|         SEARCH_REBUILD = 2, | ||||
|         SEARCH_RECURSIVE = 4, | ||||
|         SEARCH_FOREGROUND = 8 | ||||
|         private class EncodingStack | ||||
|         { | ||||
|             public SRestriction[] array; | ||||
|             public int index; | ||||
|             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); | ||||
|         } | ||||
| 
 | ||||
|     [Flags] | ||||
|     public enum SetSearchCriteriaFlags : UInt32 | ||||
|         protected override void DoRelease() | ||||
|         { | ||||
|         NONE = 0, | ||||
|         STOP_SEARCH				= 0x00000001, | ||||
|         RESTART_SEARCH			= 0x00000002, | ||||
|         RECURSIVE_SEARCH		= 0x00000004, | ||||
|         SHALLOW_SEARCH			= 0x00000008, | ||||
|         FOREGROUND_SEARCH		= 0x00000010, | ||||
|         BACKGROUND_SEARCH		= 0x00000020, | ||||
|             // TODO | ||||
|         } | ||||
| 
 | ||||
|     [ComImport] | ||||
|     [Guid("0002030B-0000-0000-C000-000000000046")] | ||||
|     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||||
|     unsafe public interface IMAPIContainer// TODO : IMAPIProp | ||||
|         public SRestriction Restriction | ||||
|         { | ||||
|         // 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); | ||||
|             get { return _root.array[0]; } | ||||
|         } | ||||
| 
 | ||||
|     [ComImport] | ||||
|     [Guid("0002030C-0000-0000-C000-000000000046")] | ||||
|     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] | ||||
|     public interface IMAPIFolder : IMAPIContainer | ||||
|         private SRestriction* Current | ||||
|         { | ||||
|         void CreateMessage(); | ||||
|         void CopyMessages(); | ||||
|         void DeleteMessages(); | ||||
|         void CreateFolder(); | ||||
|         void CopyFolder(); | ||||
|         void DeleteFolder(); | ||||
|         void SetReadFlags(); | ||||
|         void GetMessageStatus(); | ||||
|         void SetMessageStatus(); | ||||
|         void SaveContentsSort(); | ||||
|         void EmptyFolder(); | ||||
|             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(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static class RestrictionExensions | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Encodes the search as an SRestriction. | ||||
|         /// </summary> | ||||
|         /// <returns>The encoder containing the restriction. The caller is responsible for disposing.</returns> | ||||
|         public static RestrictionEncoder ToRestriction(this SearchQuery search) | ||||
|         { | ||||
|             RestrictionEncoder encoder = new RestrictionEncoder(); | ||||
|             search.Encode(encoder); | ||||
|             return encoder; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* 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 | ||||
|     } | ||||
|  | ||||
|     // 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()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user