From 98e283168a73b5df0e1aa38bb223717895d4e849 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Wed, 20 Dec 2017 14:37:53 +0200 Subject: [PATCH] [KOE-155] Implemented send-as option in shared folder dialog. Not fully working, as I cannot link it back to Outlook folders. Committing for when we can fix this. --- .../Features/ReplyFlags/FeatureReplyFlags.cs | 2 +- .../Features/SendAs/FeatureSendAs.cs | 105 ++++++++++++------ .../SharedFolders/FeatureSharedFolders.cs | 43 ++++++- .../SharedFoldersDialog.Designer.cs | 38 +++++-- .../SharedFolders/SharedFoldersDialog.cs | 67 ++++++++++- .../SharedFolders/SharedFoldersDialog.resx | 89 ++++++++++++--- .../SharedFolders/SharedFoldersManager.cs | 12 ++ .../Features/SharedFolders/StoreTreeNode.cs | 27 ++++- .../Features/SyncState/FeatureSyncState.cs | 4 +- .../AcaciaZPushPlugin/OutlookConstants.cs | 4 +- .../AcaciaZPushPlugin/Stubs/IAccount.cs | 6 + .../AcaciaZPushPlugin/Stubs/IFolder.cs | 1 + .../Stubs/OutlookWrappers/AccountWrapper.cs | 21 +++- .../Stubs/OutlookWrappers/FolderWrapper.cs | 13 ++- .../AcaciaZPushPlugin/Utils/RegistryUtil.cs | 23 ++++ .../ZPush/API/SharedFolders/SharedFolder.cs | 38 ++++++- .../AcaciaZPushPlugin/ZPush/ZPushAccount.cs | 16 +++ .../AcaciaZPushPlugin/ZPush/ZPushTypes.cs | 18 ++- 18 files changed, 448 insertions(+), 79 deletions(-) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs index c03b4fb..3eb84ef 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/ReplyFlags/FeatureReplyFlags.cs @@ -180,7 +180,7 @@ namespace Acacia.Features.ReplyFlags string id = (string)mail.GetProperty(OutlookConstants.PR_ZPUSH_MESSAGE_ID); using (IFolder folder = mail.Parent) { - string folderId = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); + string folderId = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID); string value = ReplyFlags.VerbToExchange(verb) + "/" + id + "/" + folderId; Logger.Instance.Trace(this, "Reply header: {0}", value); response.SetProperty(Constants.ZPUSH_REPLY_HEADER, value); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs index d83d2cc..bbfb564 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SendAs/FeatureSendAs.cs @@ -48,6 +48,15 @@ namespace Acacia.Features.SendAs } private static readonly BoolOption OPTION_SEND_AS_OWNER = new BoolOption("SendAsOwner", true); + [AcaciaOption("Disables GAB look ups for senders. GAB lookups are required if a username exists on different accounts, " + + "as in that case Outlook fails to determine the email address of the sender.")] + public bool GABLookup + { + get { return GetOption(OPTION_GAB_LOOKUP); } + set { SetOption(OPTION_GAB_LOOKUP, value); } + } + private static readonly BoolOption OPTION_GAB_LOOKUP = new BoolOption("GABLookup", true); + public override void Startup() { if (MailEvents != null) @@ -76,53 +85,75 @@ namespace Acacia.Features.SendAs { ZPushAccount zpush = Watcher.Accounts.GetAccount(store); Logger.Instance.Trace(this, "Checking ZPush: {0}", zpush); - if (zpush != null) + if (zpush == null) + return; + + // Check if the containing folder is a shared folder + using (IFolder parent = mail.Parent) + using (IRecipient recip = FindSendAsSender(zpush, parent)) { - // Check if the containing folder is a shared folder - using (IFolder parent = mail.Parent) + if (recip == null || !recip.IsResolved) + return; + + // Set the sender + Logger.Instance.Trace(this, "Sending as: {0}", recip.Address); + using (IAddressEntry address = recip.GetAddressEntry()) { - Logger.Instance.Trace(this, "Checking, Parent folder: {0}", parent.Name); - SharedFolder shared = _sharedFolders.GetSharedFolder(parent); - if (shared != null) - Logger.Instance.Trace(this, "Checking, Shared folder: {0}, flags={1}", shared, shared?.Flags); - else - Logger.Instance.Trace(this, "Not a shared folder"); - if (shared != null && shared.FlagSendAsOwner) - { - Logger.Instance.Trace(this, "Checking, Shared folder owner: {0}", shared.Store.UserName); - // It's a shared folder, use the owner as the sender if possible - using (IRecipient recip = FindSendAsSender(zpush, shared.Store)) - { - if (recip != null && recip.IsResolved) - { - Logger.Instance.Trace(this, "Sending as: {0}", recip.Address); - using (IAddressEntry address = recip.GetAddressEntry()) - { - response.SetSender(address); - } - } - else - { - Logger.Instance.Error(this, "Unable to resolve sender: {0}", shared.Store.UserName); - } - } - } + response.SetSender(address); } } } } - [AcaciaOption("Disables GAB look ups for senders. GAB lookups are required if a username exists on different accounts, " + - "as in that case Outlook fails to determine the email address of the sender.")] - public bool GABLookup + /// + /// Finds the sender to use for an email sent from the specified folder. + /// + /// The sender, or null if the default sender should be used + private IRecipient FindSendAsSender(ZPushAccount zpush, IFolder folder) { - get { return GetOption(OPTION_GAB_LOOKUP); } - set { SetOption(OPTION_GAB_LOOKUP, value); } - } - private static readonly BoolOption OPTION_GAB_LOOKUP = new BoolOption("GABLookup", true); + // First check if the folder is shared + if (folder.SyncId.Kind != SyncKind.Shared) + return null; - internal IRecipient FindSendAsSender(ZPushAccount zpush, GABUser user) + return FindSendAsSender(zpush, folder, folder.BackendId, null); + } + + public IRecipient FindSendAsSender(ZPushAccount zpush, IFolder folder, BackendId id, GABUser user) { + // Check for a locally stored address + if (id != null) + { + string address = zpush.GetSendAsAddress(id); + if (address != null) + { + IRecipient resolved = ThisAddIn.Instance.ResolveRecipient(address); + if (resolved != null) + return resolved; + } + } + + return null; + + // If we don't have a user, see if we can fetch it from the shared folder state + if (user == null && folder != null) + { + Logger.Instance.Trace(this, "Checking, Parent folder: {0}", folder.Name); + SharedFolder shared = _sharedFolders.GetSharedFolder(folder); + if (shared != null) + Logger.Instance.Trace(this, "Checking, Shared folder: {0}, flags={1}", shared, shared?.Flags); + else + Logger.Instance.Trace(this, "Not a shared folder"); + + if (shared != null && shared.FlagSendAsOwner) + { + user = shared.Store; + } + } + + // If we don't have a user, there's nothing to resolve + if (user == null) + return null; + // First try a simple resolve, this will work if the username is unique IRecipient recip = ThisAddIn.Instance.ResolveRecipient(user.UserName); if (recip != null) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs index 77ad82d..03ecf77 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/FeatureSharedFolders.cs @@ -1,5 +1,6 @@  using Acacia.Features.SecondaryContacts; +using Acacia.Features.SendAs; /// Copyright 2016 Kopano b.v. /// /// This program is free software: you can redistribute it and/or modify @@ -191,7 +192,7 @@ namespace Acacia.Features.SharedFolders public static bool IsSharedFolder(IFolder folder) { - string id = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); + string id = (string)folder.GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID); return id?.StartsWith("S") == true; } @@ -485,5 +486,45 @@ namespace Acacia.Features.SharedFolders Logger.Instance.Error(this, "Error removing shared store: {0}: {1}", share, e); } } + + #region Send-As helpers + + public string FindSendAsAddress(ZPushAccount account, AvailableFolder folder, string suggestion) + { + // Only mail folders have send-as + if (!folder.Type.IsMail()) + return null; + + // Check if we have send-as at all + FeatureSendAs sendAs = ThisAddIn.Instance.GetFeature(); + if (sendAs == null) + return null; + + using (IRecipient sender = sendAs.FindSendAsSender(account, null, folder.BackendId, folder.Store)) + { + if (sender != null && sender.IsResolved) + return sender.Address; + } + + return suggestion; + } + + public string FindSendAsAddress(ZPushAccount account, GABUser store, string suggestion) + { + // Check if we have send-as at all + FeatureSendAs sendAs = ThisAddIn.Instance.GetFeature(); + if (sendAs == null) + return null; + + using (IRecipient sender = sendAs.FindSendAsSender(account, null, null, store)) + { + if (sender != null && sender.IsResolved) + return sender.Address; + } + + return suggestion; + } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs index 2abd27a..852ab3e 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs @@ -45,11 +45,13 @@ this.textName = new System.Windows.Forms.TextBox(); this._labelSendAs = new System.Windows.Forms.Label(); this.checkSendAs = new System.Windows.Forms.CheckBox(); + this._labelSendAsAddress = new System.Windows.Forms.Label(); + this.textSendAsAddress = new System.Windows.Forms.TextBox(); this._labelReminders = new System.Windows.Forms.Label(); this.checkReminders = new System.Windows.Forms.CheckBox(); this._labelPermissions = new System.Windows.Forms.Label(); - this.dialogButtons = new Acacia.Controls.KDialogButtons(); this._labelRestartRequired = new System.Windows.Forms.Label(); + this.dialogButtons = new Acacia.Controls.KDialogButtons(); this._layout.SuspendLayout(); this._mainBusyHider.SuspendLayout(); this._layoutMain.SuspendLayout(); @@ -137,14 +139,16 @@ resources.ApplyResources(this._layoutOptions, "_layoutOptions"); this._layoutOptions.Controls.Add(this._labelWholeStore, 0, 0); this._layoutOptions.Controls.Add(this.checkWholeStore, 1, 0); - this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 4); + this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 5); this._layoutOptions.Controls.Add(this._labelName, 0, 1); this._layoutOptions.Controls.Add(this.textName, 1, 1); this._layoutOptions.Controls.Add(this._labelSendAs, 0, 2); this._layoutOptions.Controls.Add(this.checkSendAs, 1, 2); - this._layoutOptions.Controls.Add(this._labelReminders, 0, 3); - this._layoutOptions.Controls.Add(this.checkReminders, 1, 3); - this._layoutOptions.Controls.Add(this._labelPermissions, 0, 4); + this._layoutOptions.Controls.Add(this._labelSendAsAddress, 0, 3); + this._layoutOptions.Controls.Add(this.textSendAsAddress, 1, 3); + this._layoutOptions.Controls.Add(this._labelReminders, 0, 4); + this._layoutOptions.Controls.Add(this.checkReminders, 1, 4); + this._layoutOptions.Controls.Add(this._labelPermissions, 0, 5); this._layoutOptions.Controls.Add(this._labelRestartRequired, 2, 0); this._layoutOptions.Name = "_layoutOptions"; // @@ -192,6 +196,18 @@ this.checkSendAs.UseVisualStyleBackColor = true; this.checkSendAs.CheckedChanged += new System.EventHandler(this.checkSendAs_CheckedChanged); // + // _labelSendAsAddress + // + resources.ApplyResources(this._labelSendAsAddress, "_labelSendAsAddress"); + this._labelSendAsAddress.Name = "_labelSendAsAddress"; + // + // textSendAsAddress + // + this._layoutOptions.SetColumnSpan(this.textSendAsAddress, 2); + resources.ApplyResources(this.textSendAsAddress, "textSendAsAddress"); + this.textSendAsAddress.Name = "textSendAsAddress"; + this.textSendAsAddress.TextChanged += new System.EventHandler(this.textSendAsAddress_TextChanged); + // // _labelReminders // resources.ApplyResources(this._labelReminders, "_labelReminders"); @@ -209,6 +225,11 @@ resources.ApplyResources(this._labelPermissions, "_labelPermissions"); this._labelPermissions.Name = "_labelPermissions"; // + // _labelRestartRequired + // + resources.ApplyResources(this._labelRestartRequired, "_labelRestartRequired"); + this._labelRestartRequired.Name = "_labelRestartRequired"; + // // dialogButtons // resources.ApplyResources(this.dialogButtons, "dialogButtons"); @@ -219,11 +240,6 @@ this.dialogButtons.Name = "dialogButtons"; this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply); // - // _labelRestartRequired - // - resources.ApplyResources(this._labelRestartRequired, "_labelRestartRequired"); - this._labelRestartRequired.Name = "_labelRestartRequired"; - // // SharedFoldersDialog // resources.ApplyResources(this, "$this"); @@ -270,5 +286,7 @@ private System.Windows.Forms.CheckBox checkWholeStore; private System.Windows.Forms.Label labelPermissionsValue; private System.Windows.Forms.Label _labelRestartRequired; + private System.Windows.Forms.Label _labelSendAsAddress; + private System.Windows.Forms.TextBox textSendAsAddress; } } \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs index a543bf3..1eb8536 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs @@ -16,6 +16,7 @@ using Acacia.Controls; using Acacia.Features.GAB; +using Acacia.Features.SendAs; using Acacia.Stubs; using Acacia.UI; using Acacia.UI.Outlook; @@ -412,7 +413,8 @@ namespace Acacia.Features.SharedFolders // Add the node node = new StoreTreeNode(_folders, gabLookup.GAB, - user, user.DisplayName, currentShares ?? new Dictionary(), + user, _feature.FindSendAsAddress(_account, user, null), + user.DisplayName, currentShares ?? new Dictionary(), wholeStore); node.DirtyChanged += UserSharesChanged; node.CheckStateChanged += WholeStoreShareChanged; @@ -499,6 +501,7 @@ namespace Acacia.Features.SharedFolders set { _labelSendAs.Visible = checkSendAs.Visible = value != null; + _labelSendAsAddress.Visible = textSendAsAddress.Visible = _labelSendAs.Visible; if (value != null) checkSendAs.CheckState = value.Value; } @@ -719,6 +722,9 @@ namespace Acacia.Features.SharedFolders OptionSendAs = CheckState.Indeterminate; checkSendAs.ThreeState = true; } + + TryInitSendAsAddress(); + EnableSendAsAddress(); } // Reminders shown if any node supports it if (_optionRemindersNodes.Count > 0) @@ -791,6 +797,9 @@ namespace Acacia.Features.SharedFolders private void checkSendAs_CheckedChanged(object sender, EventArgs e) { + // Hide the address unless it makes sense + EnableSendAsAddress(); + for (int i = 0; i < _optionSendAsNodes.Count; ++i) { FolderTreeNode node = _optionSendAsNodes[i]; @@ -805,16 +814,70 @@ namespace Acacia.Features.SharedFolders if (node.SharedFolder.FlagSendAsOwner != sendAs) { node.SharedFolder = node.SharedFolder.WithFlagSendAsOwner(sendAs); + if (sendAs) + { + TryInitSendAsAddress(); + } // Send-as is applied recursively foreach (FolderTreeNode desc in node.Descendants()) { - desc.SharedFolder = desc.SharedFolder.WithFlagSendAsOwner(sendAs); + if (desc.SharedFolder != null) + { + desc.SharedFolder = desc.SharedFolder.WithFlagSendAsOwner(sendAs); + } } } } } + private void TryInitSendAsAddress() + { + string email = _feature.FindSendAsAddress(_account, _optionSendAsNodes[0].AvailableFolder, null); + + if (email != null) + { + textSendAsAddress.Text = email; + if (!string.IsNullOrEmpty(email) && _optionSendAsNodes[0].IsShared) + { + _optionSendAsNodes[0].SharedFolder.SendAsAddress = email; + } + } + else if (checkSendAs.Checked) + { + 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); + } + } + + private void EnableSendAsAddress() + { + // Hide unless there's only one selected, and send as is enabled + if (_optionSendAsNodes.Count == 1) + { + _labelSendAsAddress.Visible = textSendAsAddress.Visible = true; + _labelSendAsAddress.Enabled = textSendAsAddress.Enabled = OptionSendAs == CheckState.Checked; + } + else + { + _labelSendAsAddress.Visible = textSendAsAddress.Visible = false; + } + } + + private void textSendAsAddress_TextChanged(object sender, EventArgs e) + { + for (int i = 0; i < _optionSendAsNodes.Count; ++i) + { + FolderTreeNode node = _optionSendAsNodes[i]; + + if (node.SharedFolder.SendAsAddress != textSendAsAddress.Text) + { + node.SharedFolder = node.SharedFolder.WithSendAsAddress(textSendAsAddress.Text); + } + } + } + private void checkReminders_CheckedChanged(object sender, EventArgs e) { for (int i = 0; i < _optionRemindersNodes.Count; ++i) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx index e7b1ae9..e546473 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.resx @@ -283,7 +283,7 @@ 3, 38 - 442, 250 + 442, 224 1 @@ -394,7 +394,7 @@ NoControl - 99, 107 + 99, 133 346, 20 @@ -543,6 +543,69 @@ 6 + + True + + + Fill + + + NoControl + + + 3, 80 + + + 90, 26 + + + 11 + + + Send-as address + + + MiddleLeft + + + _labelSendAsAddress + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 7 + + + Fill + + + 102, 83 + + + 6, 3, 3, 3 + + + 343, 20 + + + 12 + + + textSendAsAddress + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutOptions + + + 8 + True @@ -550,7 +613,7 @@ Fill - 3, 80 + 3, 106 90, 27 @@ -574,7 +637,7 @@ _layoutOptions - 7 + 9 True @@ -583,7 +646,7 @@ Left - 102, 84 + 102, 110 6, 4, 3, 3 @@ -607,7 +670,7 @@ _layoutOptions - 8 + 10 True @@ -616,7 +679,7 @@ Fill - 3, 107 + 3, 133 0, 4, 0, 3 @@ -643,7 +706,7 @@ _layoutOptions - 9 + 11 Fill @@ -676,22 +739,22 @@ _layoutOptions - 10 + 12 Fill - 0, 291 + 0, 265 0, 0, 0, 0 - 5 + 6 - 448, 127 + 448, 153 2 @@ -709,7 +772,7 @@ 2 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelWholeStore" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkWholeStore" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="4" RowSpan="1" Column="1" ColumnSpan="2" /><Control Name="_labelName" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="1" RowSpan="1" Column="1" ColumnSpan="2" /><Control Name="_labelSendAs" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelReminders" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkReminders" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_labelRestartRequired" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelWholeStore" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkWholeStore" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelPermissionsValue" Row="5" RowSpan="1" Column="1" ColumnSpan="2" /><Control Name="_labelName" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textName" Row="1" RowSpan="1" Column="1" ColumnSpan="2" /><Control Name="_labelSendAs" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkSendAs" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelSendAsAddress" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="textSendAsAddress" Row="3" RowSpan="1" Column="1" ColumnSpan="2" /><Control Name="_labelReminders" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="checkReminders" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelPermissions" Row="5" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_labelRestartRequired" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0" /></TableLayoutSettings> Fill diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs index e69644d..b8dc023 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersManager.cs @@ -47,6 +47,7 @@ namespace Acacia.Features.SharedFolders } public FeatureSharedFolders Feature { get { return _feature; } } + public ZPushAccount Account { get { return _account; } } #region API @@ -57,6 +58,17 @@ namespace Acacia.Features.SharedFolders { // Make sure reminders are updated as soon as possible UpdateReminders(shares); + + // Store the send-as addresses + foreach (SharedFolder share in shares) + { + if (share.CanSendAs) + { + _account.SetSendAsAddress(share.BackendId, share.FlagSendAsOwner ? share.SendAsAddress : null); + } + } + + // Update the shares _api.SetCurrentShares(store, shares, cancel); // Commit changes diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs index 66db784..05db83b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs @@ -43,8 +43,10 @@ namespace Acacia.Features.SharedFolders private readonly Dictionary _currentShares; private readonly FeatureSharedFolders _feature; + private readonly ZPushAccount _account; private readonly GABHandler _gab; private readonly GABUser _user; + private readonly string _sendAsAddress; public readonly bool IsReadOnly; @@ -61,15 +63,21 @@ namespace Acacia.Features.SharedFolders } } - public StoreTreeNode(SharedFoldersManager folders, GABHandler gab, GABUser user, string text, + public StoreTreeNode(SharedFoldersManager folders, GABHandler gab, GABUser user, string sendAsAddress, string text, Dictionary currentFolders, bool isShared) : base(text) { this._initialShares = currentFolders; + // Patch in send as address + foreach (SharedFolder share in _initialShares.Values) + if (share.SendAsAddress == null) + share.SendAsAddress = sendAsAddress; this._feature = folders.Feature; + this._account = folders.Account; this._gab = gab; this._user = user; + this._sendAsAddress = sendAsAddress; this.IsReadOnly = false; this._isShared = isShared; @@ -155,10 +163,17 @@ namespace Acacia.Features.SharedFolders private SharedFolder CreateDefaultShare(AvailableFolder folder) { SharedFolder share = new SharedFolder(folder, DefaultNameForFolder(folder)); - - // Default send as for mail folders - if (folder.Type.IsMail()) - share = share.WithFlagSendAsOwner(true); + + // Default send as for mail folders if the address can be determined + string sendAs = _feature.FindSendAsAddress(_account, folder, _sendAsAddress); + if (sendAs != null) + { + share = share.WithFlagSendAsOwner(true).WithSendAsAddress(sendAs); + } + else + { + share = share.WithFlagSendAsOwner(false).WithSendAsAddress(null); + } return share; } @@ -218,6 +233,8 @@ namespace Acacia.Features.SharedFolders if (state.FlagUpdateShareName) state = state.WithName(DefaultNameForFolder(folder)); } + + state = state.WithSendAsAddress(_sendAsAddress); return state; } return null; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs index 1c0921b..669b217 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs @@ -501,7 +501,7 @@ namespace Acacia.Features.SyncState // Check the inbox folder using (IFolder inbox = account.Account.Store.GetDefaultFolder(DefaultFolder.Inbox)) { - string syncId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID); + string syncId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_BACKEND_ID); // If it's syncing, it's not stalled if (syncId != null && syncId != "0") @@ -515,7 +515,7 @@ namespace Acacia.Features.SyncState _syncStallLastSyncTime = sync.LastSyncTime; // Get the sync state - string folderId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); + string folderId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID); if (folderId != null) { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs index 480cb8a..a1e7d7a 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs @@ -139,8 +139,8 @@ namespace Acacia #region EAS / ZPush - public const string PR_ZPUSH_SYNC_ID = PROP + "6A18" + PT_STRING8; - public const string PR_ZPUSH_FOLDER_ID = PROP + "6A19" + PT_STRING8; + public const string PR_ZPUSH_BACKEND_ID = PROP + "6A18" + PT_STRING8; + public const string PR_ZPUSH_SYNC_ID = PROP + "6A19" + PT_STRING8; public const string PR_ZPUSH_MESSAGE_ID = PROP + "6B20" + PT_STRING8; public const string PR_ZPUSH_NAME = PROP + "6915" + PT_UNICODE; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs index dd29666..397a07c 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs @@ -74,5 +74,11 @@ namespace Acacia.Stubs } string ShareFor {get;} + + string this[string index] + { + get; + set; + } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs index 5249477..1289aea 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IFolder.cs @@ -102,6 +102,7 @@ namespace Acacia.Stubs ItemType ItemType { get; } + BackendId BackendId { get; } SyncId SyncId { get; } /// diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs index 36ef412..f5366a3 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs @@ -158,7 +158,10 @@ namespace Acacia.Stubs.OutlookWrappers { get { - return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_DEVICEID, null); + string devId = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_DEVICEID, null); + if (devId == null) + devId = RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_EAS_DEVICEID, null); + return devId; } } @@ -292,6 +295,22 @@ namespace Acacia.Stubs.OutlookWrappers } } + public string this[string index] + { + get + { + return RegistryUtil.GetValueString(_regPath, index, null); + } + + set + { + if (value == null) + RegistryUtil.RemoveValue(_regPath, index); + else + RegistryUtil.SetValueString(_regPath, index, value); + } + } + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs index e152ffd..9e3984d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/FolderWrapper.cs @@ -119,8 +119,17 @@ namespace Acacia.Stubs.OutlookWrappers { get { - string folderId = (string)GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID); - return folderId == null ? null : new SyncId(folderId); + string syncId = (string)GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID); + return syncId == null ? null : new SyncId(syncId); + } + } + + public BackendId BackendId + { + get + { + string backendId = (string)GetProperty(OutlookConstants.PR_ZPUSH_BACKEND_ID); + return backendId == null ? null : new BackendId(backendId); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs index 4eb4aa2..a8ebd9a 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs @@ -45,6 +45,29 @@ namespace Acacia.Utils Registry.SetValue(keyPath, valueName, value); } + public static void RemoveValue(string keyPath, string valueName) + { + using (RegistryKey key = KeyFromPath(keyPath, true)) + { + if (key != null) + { + key.DeleteValue(valueName, false); + } + } + } + + private static RegistryKey KeyFromPath(string keyPath, bool writeable) + { + foreach (RegistryKey baseKey in new RegistryKey[] {Registry.CurrentUser, Registry.LocalMachine }) + { + if (keyPath.StartsWith(baseKey.Name)) + { + return baseKey.OpenSubKey(keyPath.Substring(baseKey.Name.Length + 1), writeable); + } + } + return null; + } + public static string RegToString(object o) { if (o is byte[]) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs index c7fa0ca..d8fab76 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs @@ -163,7 +163,14 @@ namespace Acacia.ZPush.API.SharedFolders { SoapData newData = _data; newData.flags = flags; - return new SharedFolder(newData); + SharedFolder clone = new SharedFolder(newData); + clone.SendAsAddress = SendAsAddress; + return clone; + } + + public bool CanSendAs + { + get { return SyncType.IsMail(); } } public bool FlagSendAsOwner { get { return Flags.HasFlag(ShareFlags.SendAsOwner); } } @@ -196,6 +203,23 @@ namespace Acacia.ZPush.API.SharedFolders #endregion + #region Send as + + public string SendAsAddress + { + get; + set; + } + + public SharedFolder WithSendAsAddress(string sendAs) + { + SharedFolder clone = new SharedFolder(_data); + clone.SendAsAddress = sendAs; + return clone; + } + + #endregion + #region Standard overrides public override int GetHashCode() @@ -205,7 +229,17 @@ namespace Acacia.ZPush.API.SharedFolders override public bool Equals(object o) { - return o is SharedFolder && _data.Equals(((SharedFolder)o)._data); + SharedFolder rhs = o as SharedFolder; + if (rhs == null) + return false; + + if (!_data.Equals(rhs._data)) + return false; + + if (!FlagSendAsOwner) + return true; + + return Object.Equals(SendAsAddress, rhs.SendAsAddress); } public override string ToString() diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs index 4395ffc..bcdcb58 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs @@ -284,5 +284,21 @@ namespace Acacia.ZPush } #endregion + + #region Send as + + private const string PREFIX_SEND_AS = "KOE SendAs "; + + public void SetSendAsAddress(BackendId id, string sendAsAddress) + { + _account[PREFIX_SEND_AS + id.ToString()] = sendAsAddress; + } + + public string GetSendAsAddress(BackendId id) + { + return _account[PREFIX_SEND_AS + id.ToString()]; + } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs index a5bd0ad..18347a1 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs @@ -118,7 +118,23 @@ namespace Acacia.ZPush { public static readonly BackendId NONE = new BackendId("0"); - public BackendId(string id) : base(id) { } + public BackendId(string id) + : + base(StripSuffix(id)) + { + } + + private static string StripSuffix(string id) + { + // The backend id is of the format {id}num?. Strip off num if present + int index = id.IndexOf('}'); + if (index >= 0 && index < id.Length) + { + id = id.Substring(0, index + 1); + } + return id; + } + public BackendId(int id) : base(id) { } public BackendId(long id) : base(id.ToString()) { }