diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs index 25cce3e..446ccf2 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs @@ -26,6 +26,7 @@ using Acacia.Features.SharedFolders; using Acacia.ZPush.API.SharedFolders; using static Acacia.DebugOptions; using Acacia.Features.GAB; +using Acacia.Features.SyncState; namespace Acacia.Features.SendAs { @@ -158,6 +159,42 @@ namespace Acacia.Features.SendAs #region Address resolving + public string FindSendAsAddress(ZPushAccount zpush, SharedFolder folder) + { + string address = folder.SendAsAddress; + if (!string.IsNullOrWhiteSpace(address)) + return address; + + // Check the registry + string addressSync = zpush.GetSendAsAddress(folder.SyncId); + string addressBackend = zpush.GetSendAsAddress(folder.BackendId); + // If we have no address on sync id, or it differs from the one on backend id, backend id wins, as that's the one set by the dialog + if (string.IsNullOrWhiteSpace(addressSync) || !addressSync.Equals(addressBackend)) + { + address = addressBackend; + // Resolved now, store on sync id + if (folder.SyncId.IsCustom) + zpush.SetSendAsAddress(folder.SyncId, address); + } + else address = addressSync; + + return address; + } + + internal void UpdateSendAsAddresses(ZPushAccount zpush, ICollection shares) + { + SyncState.SyncState state = ThisAddIn.Instance.GetFeature()?.GetSyncState(zpush); + + foreach (SharedFolder folder in shares) + { + if (!folder.FlagSendAsOwner) + continue; + + // Resolve it + FindSendAsAddress(zpush, folder); + } + } + public string FindSendAsAddress(ZPushAccount zpush, GABUser user) { GABHandler handler = FeatureGAB.FindGABForAccount(zpush); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs index daf458b..6c64d86 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs @@ -1,7 +1,4 @@ - -using Acacia.Features.SecondaryContacts; -using Acacia.Features.SendAs; -/// Copyright 2016 Kopano b.v. +/// Copyright 2018 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, @@ -16,6 +13,9 @@ using Acacia.Features.SendAs; /// along with this program.If not, see. /// /// Consult LICENSE file for details + +using Acacia.Features.SecondaryContacts; +using Acacia.Features.SendAs; using Acacia.Stubs; using Acacia.UI; using Acacia.UI.Outlook; @@ -143,9 +143,20 @@ namespace Acacia.Features.SharedFolders private void AdditionalFolders_Sync(ZPushConnection connection) { - using (SharedFoldersManager manager = Manage(connection.Account)) + SyncShares(connection.Account); + } + + public void Sync(ZPushAccount account) + { + Watcher.Sync.Resync(); + account.Account.SendReceive(); + } + + private void SyncShares(ZPushAccount account) + { + using (SharedFoldersManager manager = Manage(account)) { - Logger.Instance.Debug(this, "Starting sync for account {0}", connection.Account); + Logger.Instance.Debug(this, "Starting sync for account {0}", account); // Fetch the current shares ICollection shares = manager.GetCurrentShares(null); @@ -157,11 +168,10 @@ namespace Acacia.Features.SharedFolders // Store any send-as properties FeatureSendAs sendAs = ThisAddIn.Instance.GetFeature(); - // TODO - //sendAs?.UpdateSendAsAddresses(connection.Account, shares); + sendAs?.UpdateSendAsAddresses(account, shares); // Store with the account - connection.Account.SetFeatureData(this, KEY_SHARES, dict); + account.SetFeatureData(this, KEY_SHARES, dict); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs index c6f8742..254cdbe 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs @@ -256,6 +256,35 @@ namespace Acacia.Features.SharedFolders private void dialogButtons_Apply(object sender, EventArgs e) { + // Check if all fields are properly set + foreach (StoreTreeNode storeNode in _userFolders.Values) + { + // Check modified folders + if (storeNode.IsDirty) + { + foreach(SharedFolder folder in storeNode.CurrentShares) + { + // Check if the send-as address has been resolved (or entered) correctly + if (folder.FlagSendAsOwner && string.IsNullOrWhiteSpace(folder.SendAsAddress)) + { + // Select the node if we can + KTreeNode folderNode = storeNode.FindNode(folder); + if (folderNode != null) + { + // If the node is already selected, explicitly warn about the send-as address + // Otherwise, selecting it will pop up the warning + if (folderNode.IsSelected) + TryInitSendAsAddress(); + else + FocusNode(folderNode, false); + } + return; + } + } + } + } + + BusyText = Properties.Resources.SharedFolders_Applying_Label; KUITask.New((ctx) => { @@ -270,6 +299,10 @@ namespace Acacia.Features.SharedFolders ctx.AddBusy(1); ++state.folders; + // Check removed shares + _folders.RemoveSharesForStore(storeNode.User, storeNode.RemovedShares); + + // Set shares _folders.SetSharesForStore(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken); } @@ -343,17 +376,17 @@ namespace Acacia.Features.SharedFolders foreach (StoreTreeNode storeNode in _userFolders.Values) storeNode.ChangesApplied(); CheckDirty(); - - if (state.folders != 0) - { - // Sync account - _account.Account.SendReceive(); - - // Show success - ShowCompletion(Properties.Resources.SharedFolders_Applying_Success); - } - } + + if (state.folders != 0) + { + // Sync account + _feature.Sync(_account); + + // Show success + ShowCompletion(Properties.Resources.SharedFolders_Applying_Success); + } + }, true) .OnError((x) => { @@ -438,7 +471,8 @@ namespace Acacia.Features.SharedFolders kTreeFolders.SelectNode(node, KTree.ScrollMode.Top); // Start loading folders if requested - node.IsExpanded = expand; + if (expand) + node.IsExpanded = true; // Clear any selected user gabLookup.SelectedUser = null; @@ -837,25 +871,21 @@ namespace Acacia.Features.SharedFolders private void TryInitSendAsAddress() { - string email = null; - /*_featureSendAs?.FindSendAsAddress(_account, null, - _optionSendAsNodes[0].AvailableFolder.BackendId, - _optionSendAsNodes[0].AvailableFolder.Store;)*/ + // Initialise to the send-as address specified for an existing share, or a simple GAB lookup otherwise + string email = + _optionSendAsNodes[0].SharedFolder?.SendAsAddress ?? + _featureSendAs?.FindSendAsAddress(_account, _optionSendAsNodes[0].AvailableFolder.Store); - if (email != null) + if (!string.IsNullOrEmpty(email)) { textSendAsAddress.Text = email; - if (!string.IsNullOrEmpty(email) && _optionSendAsNodes[0].IsShared) - { - _optionSendAsNodes[0].SharedFolder.SendAsAddress = email; - } + _optionSendAsNodes[0].SharedFolder.SendAsAddress = email; } else if (checkSendAs.Checked) { - // TODO: resource string - MessageBox.Show("Unable to determine the email address for the folder. " + - "Send-as will only work if you specify the email address manually.", - "Shared Folders", MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show(Properties.Resources.SharedFolders_SendAsFailed_Label, + Properties.Resources.SharedFolders_SendAsFailed_Title, + MessageBoxButtons.OK, MessageBoxIcon.Information); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs index fc2184a..7947813 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs @@ -8,6 +8,7 @@ using Acacia.ZPush; using Acacia.ZPush.API.SharedFolders; using System.Threading; using Acacia.Native.MAPI; +using Acacia.Features.SendAs; namespace Acacia.Features.SharedFolders { @@ -51,6 +52,16 @@ namespace Acacia.Features.SharedFolders #region API + public void RemoveSharesForStore(GABUser store, ICollection removed) + { + foreach(SharedFolder folder in removed) + { + if (folder.SyncId != null) + _account.SetSendAsAddress(folder.SyncId, null); + _account.SetSendAsAddress(folder.BackendId, null); + } + } + /// /// Sets all shares for the specified store. /// @@ -94,6 +105,15 @@ namespace Acacia.Features.SharedFolders ); } + // Patch in the send-as addresses + foreach (SharedFolder folder in shares) + { + if (folder.FlagSendAsOwner && string.IsNullOrWhiteSpace(folder.SendAsAddress)) + { + folder.SendAsAddress = ThisAddIn.Instance.GetFeature()?.FindSendAsAddress(_account, folder); + } + } + // Commit changes if (_query != null) _query.Commit(); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs index a87b15f..0f6926f 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs @@ -74,7 +74,7 @@ namespace Acacia.Features.SharedFolders this._initialShares = currentFolders; // Patch in send as address foreach (SharedFolder share in _initialShares.Values) - if (share.SendAsAddress == null) + if (string.IsNullOrWhiteSpace(share.SendAsAddress)) share.SendAsAddress = sendAsAddress; this._feature = folders.Feature; this._featureSendAs = ThisAddIn.Instance.GetFeature(); @@ -191,6 +191,20 @@ namespace Acacia.Features.SharedFolders } } + internal ICollection RemovedShares + { + get + { + List removed = new List(); + foreach(SharedFolder folder in _initialShares.Values) + { + if (!_currentShares.ContainsKey(folder.BackendId)) + removed.Add(folder); + } + return removed; + } + } + internal string DefaultNameForFolder(AvailableFolder folder) { // Default include the store name in root folders @@ -239,7 +253,8 @@ namespace Acacia.Features.SharedFolders state = state.WithName(DefaultNameForFolder(folder)); } - state = state.WithSendAsAddress(_sendAsAddress); + if (string.IsNullOrWhiteSpace(state.SendAsAddress)) + state = state.WithSendAsAddress(_sendAsAddress); return state; } return null; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs index 2a8cd24..ccb844b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs @@ -1166,6 +1166,24 @@ namespace Acacia.Properties { } } + /// + /// Looks up a localized string similar to Unable to determine the email address for the folder. Send-as will only work if you specify the email address manually.. + /// + internal static string SharedFolders_SendAsFailed_Label { + get { + return ResourceManager.GetString("SharedFolders_SendAsFailed_Label", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shared Folders. + /// + internal static string SharedFolders_SendAsFailed_Title { + get { + return ResourceManager.GetString("SharedFolders_SendAsFailed_Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to There are unsaved changes. Do you really want to to discard these?. /// diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx index 78f7346..737d12e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx @@ -530,4 +530,10 @@ Please contact your system administrator for any required changes. Open stores + + Unable to determine the email address for the folder. Send-as will only work if you specify the email address manually. + + + Shared Folders + \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs index 9042aaa..3240b00 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs @@ -58,5 +58,11 @@ namespace Acacia.Stubs string RegistryBaseKey { get; } void SetAccountProp(PropTag prop, object value); + + string this[string name] + { + get; + set; + } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs index d8fab76..7eaff52 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs @@ -147,7 +147,7 @@ namespace Acacia.ZPush.API.SharedFolders { SoapData newData = _data; newData.name = name; - return new SharedFolder(newData); + return DoClone(newData); } #endregion @@ -163,6 +163,11 @@ namespace Acacia.ZPush.API.SharedFolders { SoapData newData = _data; newData.flags = flags; + return DoClone(newData); + } + + private SharedFolder DoClone(SoapData newData) + { SharedFolder clone = new SharedFolder(newData); clone.SendAsAddress = SendAsAddress; return clone; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs index f6a262f..4e6bc4b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs @@ -390,26 +390,27 @@ namespace Acacia.ZPush #region Send as - private const string PREFIX_SEND_AS = "KOE SendAs "; + private const string PREFIX_SEND_AS_SYNC = "KOE SendAs Sync "; + private const string PREFIX_SEND_AS_BACKEND = "KOE SendAs Backend "; public void SetSendAsAddress(BackendId id, string sendAsAddress) { - RegistryUtil.SetValueString(Account.RegistryBaseKey, PREFIX_SEND_AS + id.ToString(), sendAsAddress); + _account[PREFIX_SEND_AS_BACKEND + id] = sendAsAddress; } public string GetSendAsAddress(BackendId id) { - return RegistryUtil.GetValueString(Account.RegistryBaseKey, PREFIX_SEND_AS + id.ToString(), null); + return _account[PREFIX_SEND_AS_BACKEND + id]; } public void SetSendAsAddress(SyncId id, string sendAsAddress) { - RegistryUtil.SetValueString(Account.RegistryBaseKey, PREFIX_SEND_AS + id.ToString(), sendAsAddress); + _account[PREFIX_SEND_AS_SYNC + id] = sendAsAddress; } public string GetSendAsAddress(SyncId id) { - return RegistryUtil.GetValueString(Account.RegistryBaseKey, PREFIX_SEND_AS + id.ToString(), null); + return _account[PREFIX_SEND_AS_SYNC + id]; } #endregion diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs index 7efdc06..0d5ce13 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushSync.cs @@ -282,6 +282,11 @@ namespace Acacia.ZPush _started = true; } + public void Resync() + { + LastSyncTime = new DateTime(); + } + /// /// Delegate for an account-specific task. ///