diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs index aadb251..475187f 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/GAB/FeatureGAB.cs @@ -39,7 +39,7 @@ namespace Acacia.Features.GAB private readonly Dictionary _gabsByDomainName = new Dictionary(); private readonly HashSet _gabFolders = new HashSet(); private readonly HashSet _domains = new HashSet(); - private ZPushLocalStore _store; + private IStore _store; private int _processing; public FeatureGAB() @@ -316,11 +316,11 @@ namespace Acacia.Features.GAB // Delete any contacts folders in the local store if (DeleteExistingFolder) { - using (ZPushLocalStore store = ZPushLocalStore.GetInstance(ThisAddIn.Instance)) + using (IStore store = ZPushLocalStore.GetInstance(ThisAddIn.Instance)) { if (store != null) { - using (IFolder root = store.RootFolder) + using (IFolder root = store.GetRootFolder()) { foreach (IFolder folder in root.GetSubFolders()) { @@ -416,7 +416,7 @@ namespace Acacia.Features.GAB return null; // Try to find the existing GAB - using (IFolder root = _store.RootFolder) + using (IFolder root = _store.GetRootFolder()) { IAddressBook gab = FindGABForDomain(root, domainName); if (gab == null) @@ -538,7 +538,7 @@ namespace Acacia.Features.GAB return; bool deletedSomething = false; - using (IFolder root = _store.RootFolder) + using (IFolder root = _store.GetRootFolder()) { foreach (IFolder subfolder in root.GetSubFolders()) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs index ed384be..4a07b11 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs @@ -57,6 +57,13 @@ namespace Acacia.Stubs IRecipient ResolveRecipient(string name); + IStore AddFileStore(string path); + + /// + /// Returns the stores. The caller is responsible for disposing. + /// + IEnumerable Stores { get; } + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs index 9130f06..13aca83 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs @@ -54,6 +54,7 @@ namespace Acacia.Stubs IEnumerable GetSubFolders() where FolderType : IFolder; + IEnumerable GetSubFolders(); FolderType GetSubFolder(string name) where FolderType : IFolder; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs index 51c0523..f14e12d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IStore.cs @@ -24,9 +24,18 @@ namespace Acacia.Stubs { public interface IStore : IDisposable { + /// + /// Returns the root folder. + /// + /// The root folder. The caller is responsible for disposing. IFolder GetRootFolder(); IItem GetItemFromID(string id); string DisplayName { get; } string StoreID { get; } + + bool IsFileStore { get; } + string FilePath { get; } + + void EmptyDeletedItems(); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs index b2cbe70..ebad830 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AddInWrapper.cs @@ -94,7 +94,7 @@ namespace Acacia.Stubs.OutlookWrappers Microsoft.Office.Core.COMAddIns addIns = _app.COMAddIns; try { - foreach(Microsoft.Office.Core.COMAddIn comAddin in addIns) + foreach (Microsoft.Office.Core.COMAddIn comAddin in addIns) { try { @@ -196,13 +196,44 @@ namespace Acacia.Stubs.OutlookWrappers using (ComRelease com = new ComRelease()) { NSOutlook.NameSpace session = com.Add(_app.Session); - NSOutlook.Recipient recipient = session.CreateRecipient(name); + // Add recipient, unlock after Resolve (which might throw) to wrap + NSOutlook.Recipient recipient = com.Add(session.CreateRecipient(name)); if (recipient == null) return null; - com.Add(recipient); recipient.Resolve(); return Mapping.Wrap(com.Remove(recipient)); } } + + public IStore AddFileStore(string path) + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.NameSpace session = com.Add(_app.Session); + + // Add the store + session.AddStore(path); + + // And fetch it and wrap + NSOutlook.Stores stores = com.Add(session.Stores); + return StoreWrapper.Wrap(stores[stores.Count]); + } + } + + public IEnumerable Stores + { + get + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.NameSpace session = com.Add(_app.Session); + NSOutlook.Stores stores = com.Add(session.Stores); + foreach (NSOutlook.Store store in stores) + { + yield return StoreWrapper.Wrap(store); + } + } + } + } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs index 2361b09..d19678b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs @@ -296,6 +296,11 @@ namespace Acacia.Stubs.OutlookWrappers }; } + public IEnumerable GetSubFolders() + { + return GetSubFolders(); + } + public FolderType GetSubFolder(string name) where FolderType : IFolder { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs index 30f1241..675c292 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/StoreWrapper.cs @@ -24,9 +24,9 @@ using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.Stubs.OutlookWrappers { - public class StoreWrapper : ComWrapper, IStore + class StoreWrapper : ComWrapper, IStore { - public static IStore Wrap(NSOutlook.Store store) + internal static IStore Wrap(NSOutlook.Store store) { return store == null ? null : new StoreWrapper(store); } @@ -64,5 +64,30 @@ namespace Acacia.Stubs.OutlookWrappers public string DisplayName { get { return _store.DisplayName; } } public string StoreID { get { return _store.StoreID; } } + + public bool IsFileStore { get { return _store.IsDataFileStore; } } + public string FilePath { get { return _store.FilePath; } } + + public void EmptyDeletedItems() + { + using (ComRelease com = new ComRelease()) + { + NSOutlook.MAPIFolder f = _store.GetDefaultFolder(NSOutlook.OlDefaultFolders.olFolderDeletedItems); + if (f != null) + { + com.Add(f); + + // Normal enumeration fails when deleting. Do it like this. + NSOutlook.Folders folders = com.Add(f.Folders); + for (int i = folders.Count; i > 0; --i) + com.Add(folders[i]).Delete(); + + NSOutlook.Items items = com.Add(f.Items); + for (int i = items.Count; i > 0; --i) + com.Add(items[i]).Delete(); + } + } + } + } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs index faa31f2..643b266 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushLocalStore.cs @@ -30,58 +30,32 @@ namespace Acacia.ZPush /// /// Manages a local store in which Z-Push data is stored. /// - /// TODO: merge with Store where possible - public class ZPushLocalStore : ComWrapper + public static class ZPushLocalStore { - private NSOutlook.Store _store; - - public IFolder RootFolder + /// + /// Returns or creates the local store. + /// + /// The store, or null on error. If a store is returned, the caller is responsible for disposing. + public static IStore GetInstance(IAddIn addIn) { - get + IStore store = OpenOrCreateInstance(addIn); + if (store == null) + return null; + + try { - return Mapping.Wrap(_store.GetRootFolder()); + HideAllFolders(store); + return store; + } + catch(Exception e) + { + store.Dispose(); + throw e; } } - public string StoreId { get { return _store.StoreID; } } - - private ZPushLocalStore(NSOutlook.Store store) - { - this._store = store; - HideAllFolders(); - } - - protected override void DoRelease() - { - ComRelease.Release(_store); - _store = null; - } - - private bool IsCustomFolder(IFolder folder) - { - return Features.GAB.FeatureGAB.IsGABContactsFolder(folder); - } - - private void HideAllFolders() - { - if (GlobalOptions.INSTANCE.LocalFolders_Hide) - { - // Hide the folders that are not custom folders - using (ComRelease com = new ComRelease()) - { - foreach (NSOutlook.Folder sub in com.Add(com.Add(_store.GetRootFolder()).Folders)) - { - using (IFolder wrapped = Mapping.Wrap(sub)) - { - wrapped.AttrHidden = !IsCustomFolder(wrapped); - } - } - } - } - } - - public static ZPushLocalStore GetInstance(IAddIn addIn) - { + private static IStore OpenOrCreateInstance(IAddIn addIn) + { try { // Try to find the existing store @@ -94,9 +68,9 @@ namespace Acacia.ZPush Logger.Instance.Debug(typeof(ZPushLocalStore), "Opening store with prefix {0}", prefix); // See if a store with this prefix exists - NSOutlook.Store store = FindInstance(addIn, prefix); + IStore store = FindInstance(addIn, prefix); if (store != null) - return new ZPushLocalStore(store); + return store; // Doesn't exist, create it Logger.Instance.Debug(typeof(ZPushLocalStore), "No existing store found"); @@ -114,8 +88,7 @@ namespace Acacia.ZPush // Path found, create the store Logger.Instance.Info(typeof(ZPushLocalStore), "Creating new store: {0}", path); - addIn.RawApp.Session.AddStore(path); - store = addIn.RawApp.Session.Stores[addIn.RawApp.Session.Stores.Count]; + store = addIn.AddFileStore(path); Logger.Instance.Debug(typeof(ZPushLocalStore), "Created new store: {0}", store.FilePath); // Set the display name @@ -125,7 +98,7 @@ namespace Acacia.ZPush } // Done - return new ZPushLocalStore(store); + return store; } catch(System.Exception e) { @@ -134,38 +107,42 @@ namespace Acacia.ZPush } } - private static NSOutlook.Store FindInstance(IAddIn addIn, string prefix) + private static IStore FindInstance(IAddIn addIn, string prefix) { - foreach (NSOutlook.Store store in addIn.RawApp.Session.Stores) + foreach (IStore store in addIn.Stores) { - if (store.IsDataFileStore && store.FilePath.StartsWith(prefix)) + if (store.IsFileStore && store.FilePath.StartsWith(prefix)) { Logger.Instance.Info(typeof(ZPushLocalStore), "Opening existing store: {0}", store.FilePath); return store; } + else + { + store.Dispose(); + } } return null; } - internal void EmptyDeletedItems() + private static bool IsCustomFolder(IFolder folder) { - using (ComRelease com = new ComRelease()) + return Features.GAB.FeatureGAB.IsGABContactsFolder(folder); + } + + private static void HideAllFolders(IStore store) + { + if (GlobalOptions.INSTANCE.LocalFolders_Hide) { - NSOutlook.MAPIFolder f = _store.GetDefaultFolder(NSOutlook.OlDefaultFolders.olFolderDeletedItems); - if (f != null) + // Hide the folders that are not custom folders + using (ComRelease com = new ComRelease()) { - com.Add(f); - - // Normal enumeration fails when deleting. Do it like this. - NSOutlook.Folders folders = com.Add(f.Folders); - for (int i = folders.Count; i > 0; --i) - com.Add(folders[i]).Delete(); - - NSOutlook.Items items = com.Add(f.Items); - for (int i = items.Count; i > 0; --i) - com.Add(items[i]).Delete(); + foreach(IFolder sub in store.GetRootFolder().GetSubFolders()) + { + sub.AttrHidden = !IsCustomFolder(sub); + } } } } + } }