From 8c08363b1f5d8596520dc4272cf97a85f40716d0 Mon Sep 17 00:00:00 2001 From: Patrick Simpson Date: Wed, 28 Feb 2018 17:00:51 +0200 Subject: [PATCH] [KOE-76] Implemented per-account sync timeframe in sync dialog --- .../AcaciaZPushPlugin/Controls/KDialogNew.cs | 1 + .../Features/Signatures/FeatureSignatures.cs | 14 +- .../Features/SyncState/FeatureSyncState.cs | 45 ++- .../SyncState/SyncStateDialog.Designer.cs | 70 +++- .../Features/SyncState/SyncStateDialog.cs | 66 +++- .../Features/SyncState/SyncStateDialog.resx | 327 +++++++++++++----- .../Features/WebApp/FeatureWebApp.cs | 4 +- .../AcaciaZPushPlugin/Native/IOlkAccount.cs | 7 +- .../AcaciaZPushPlugin/Native/MAPI/Property.cs | 9 + .../AcaciaZPushPlugin/OutlookConstants.cs | 11 +- .../AcaciaZPushPlugin/Stubs/IAccount.cs | 26 +- .../Stubs/OutlookWrappers/AccountWrapper.cs | 109 +++--- .../AcaciaZPushPlugin/Utils/RegistryUtil.cs | 11 + .../AcaciaZPushPlugin/ZPush/ZPushAccount.cs | 113 +++++- .../AcaciaZPushPlugin/ZPush/ZPushTypes.cs | 13 + 15 files changed, 613 insertions(+), 213 deletions(-) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs index 778e652..7bde0f3 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KDialogNew.cs @@ -70,6 +70,7 @@ namespace Acacia.Controls #endregion #region KUITaskProgress + // TODO: if BusyHider is not set, pop up dialogs public string BusyText { diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Signatures/FeatureSignatures.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Signatures/FeatureSignatures.cs index e2c0576..08c956d 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Signatures/FeatureSignatures.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/Signatures/FeatureSignatures.cs @@ -134,7 +134,7 @@ namespace Acacia.Features.Signatures if (serverSignatureHash != null) { Logger.Instance.Trace(this, "Checking signature hash for account {0}: {1}", account, serverSignatureHash); - if (serverSignatureHash == account.Account.LocalSignaturesHash) + if (serverSignatureHash == account.LocalSignaturesHash) return; } @@ -145,7 +145,7 @@ namespace Acacia.Features.Signatures string hash = FetchSignatures(account); // Store updated hash - account.Account.LocalSignaturesHash = hash; + account.LocalSignaturesHash = hash; Logger.Instance.Debug(this, "Updated signatures: {0}: {1}", account, hash); } catch (Exception e) @@ -206,13 +206,13 @@ namespace Acacia.Features.Signatures } // Set default signatures if available and none are set - if (!string.IsNullOrEmpty(result.new_message) && ShouldSetSignature(account.Account.SignatureNewMessage)) + if (!string.IsNullOrEmpty(result.new_message) && ShouldSetSignature(account.SignatureNewMessage)) { - account.Account.SignatureNewMessage = fullNames[result.new_message]; + account.SignatureNewMessage = fullNames[result.new_message]; } - if (!string.IsNullOrEmpty(result.replyforward_message) && ShouldSetSignature(account.Account.SignatureReplyForwardMessage)) + if (!string.IsNullOrEmpty(result.replyforward_message) && ShouldSetSignature(account.SignatureReplyForwardMessage)) { - account.Account.SignatureReplyForwardMessage = fullNames[result.replyforward_message]; + account.SignatureReplyForwardMessage = fullNames[result.replyforward_message]; } return result.hash; @@ -291,7 +291,7 @@ namespace Acacia.Features.Signatures private void GAB_SyncFinished(GABHandler gab) { - ReplacePlaceholders(gab, gab.ActiveAccount.Account.SignatureNewMessage, gab.ActiveAccount.Account.SignatureNewMessage); + ReplacePlaceholders(gab, gab.ActiveAccount.SignatureNewMessage, gab.ActiveAccount.SignatureNewMessage); } private void ReplacePlaceholders(GABHandler gab, params string[] signatures) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs index 1c0921b..136c3ad 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs @@ -1,4 +1,4 @@ -/// Copyright 2017 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, @@ -576,10 +576,13 @@ namespace Acacia.Features.SyncState if (_dialog != null) return; + // Get the current account. If no Z-Push account is selected, the dialog will open for all accounts. + ZPushAccount account = Watcher.CurrentZPushAccount(); + // Ramp up the checking schedule while the dialog is open // The other check sets per-account schedules, we use the global one, so they should't interfere. TimeSpan? old = Watcher.Sync.SetTaskSchedule(_task, null, CheckPeriodDialogEffective, true); - SyncStateDialog dlg = new SyncStateDialog(this); + SyncStateDialog dlg = new SyncStateDialog(this, account); dlg.FormClosed += (s, e) => { // Restore the schedule @@ -733,5 +736,43 @@ namespace Acacia.Features.SyncState { return new SyncStateImpl(this, account == null ? Watcher.Accounts.GetAccounts().ToArray() : new ZPushAccount[] { account }); } + + + private class SetDeviceOptionsRequest : SoapRequest + { + public SetDeviceOptionsRequest(SyncTimeFrame timeFrame) + { + Parameters.Add("filtertype", (int)timeFrame); + } + } + + public void SetDeviceOptions(ZPushAccount account, SyncTimeFrame timeFrame) + { + + try + { + Logger.Instance.Debug(this, "Setting sync time frame for {0} to {1}", account, timeFrame); + + // First set the server value. + using (ZPushConnection connection = account.Connect()) + using (ZPushWebServiceDevice deviceService = connection.DeviceService) + { + deviceService.Execute(new SetDeviceOptionsRequest(timeFrame)); + } + + // And the local value + account.SyncTimeFrame = timeFrame; + Logger.Instance.Debug(this, "Set sync time frame for {0} to {1}", account, timeFrame); + + // Sync + ThisAddIn.Instance.SendReceive(account.Account); + } + catch (Exception x) + { + Logger.Instance.Warning(this, "Exception setting sync time frame for {0} to {1}: {2}", account, timeFrame, x); + } + + + } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.Designer.cs index 4c3a2dd..ea558fa 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.Designer.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.Designer.cs @@ -38,6 +38,11 @@ this._labelProgress = new System.Windows.Forms.Label(); this.progress = new Acacia.Controls.KProgressBar(); this.textRemaining = new System.Windows.Forms.Label(); + this._labelTimeFrame = new System.Windows.Forms.Label(); + this._layoutTimeFrameButtons = new System.Windows.Forms.TableLayoutPanel(); + this.comboTimeFrame = new System.Windows.Forms.ComboBox(); + this.buttonApplyTimeFrame = new System.Windows.Forms.Button(); + this.buttonResetTimeFrame = new System.Windows.Forms.Button(); this._labelResync = new System.Windows.Forms.Label(); this.buttonGAB = new Acacia.Controls.KHintButton(); this.buttonSignatures = new Acacia.Controls.KHintButton(); @@ -46,6 +51,7 @@ this._labelResyncOption = new System.Windows.Forms.Label(); this._layout.SuspendLayout(); this._layoutMain.SuspendLayout(); + this._layoutTimeFrameButtons.SuspendLayout(); this.SuspendLayout(); // // _layout @@ -73,12 +79,14 @@ this._layoutMain.Controls.Add(this._labelProgress, 0, 1); this._layoutMain.Controls.Add(this.progress, 1, 1); this._layoutMain.Controls.Add(this.textRemaining, 1, 2); - this._layoutMain.Controls.Add(this._labelResync, 0, 3); - this._layoutMain.Controls.Add(this.buttonGAB, 1, 3); - this._layoutMain.Controls.Add(this.buttonSignatures, 1, 4); - this._layoutMain.Controls.Add(this.buttonServerData, 1, 5); - this._layoutMain.Controls.Add(this.buttonFullResync, 1, 6); - this._layoutMain.Controls.Add(this._labelResyncOption, 1, 7); + this._layoutMain.Controls.Add(this._labelTimeFrame, 0, 3); + this._layoutMain.Controls.Add(this._layoutTimeFrameButtons, 1, 3); + this._layoutMain.Controls.Add(this._labelResync, 0, 6); + this._layoutMain.Controls.Add(this.buttonGAB, 1, 6); + this._layoutMain.Controls.Add(this.buttonSignatures, 1, 7); + this._layoutMain.Controls.Add(this.buttonServerData, 1, 8); + this._layoutMain.Controls.Add(this.buttonFullResync, 1, 9); + this._layoutMain.Controls.Add(this._labelResyncOption, 1, 10); this._layoutMain.Name = "_layoutMain"; // // _labelRemaining @@ -121,6 +129,50 @@ this.textRemaining.BackColor = System.Drawing.SystemColors.Window; this.textRemaining.Name = "textRemaining"; // + // _labelTimeFrame + // + resources.ApplyResources(this._labelTimeFrame, "_labelTimeFrame"); + this._labelTimeFrame.Name = "_labelTimeFrame"; + // + // _layoutTimeFrameButtons + // + resources.ApplyResources(this._layoutTimeFrameButtons, "_layoutTimeFrameButtons"); + this._layoutTimeFrameButtons.Controls.Add(this.comboTimeFrame, 0, 0); + this._layoutTimeFrameButtons.Controls.Add(this.buttonApplyTimeFrame, 2, 0); + this._layoutTimeFrameButtons.Controls.Add(this.buttonResetTimeFrame, 1, 0); + this._layoutTimeFrameButtons.Name = "_layoutTimeFrameButtons"; + // + // comboTimeFrame + // + resources.ApplyResources(this.comboTimeFrame, "comboTimeFrame"); + this.comboTimeFrame.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboTimeFrame.FormattingEnabled = true; + this.comboTimeFrame.Items.AddRange(new object[] { + resources.GetString("comboTimeFrame.Items"), + resources.GetString("comboTimeFrame.Items1"), + resources.GetString("comboTimeFrame.Items2"), + resources.GetString("comboTimeFrame.Items3"), + resources.GetString("comboTimeFrame.Items4"), + resources.GetString("comboTimeFrame.Items5"), + resources.GetString("comboTimeFrame.Items6"), + resources.GetString("comboTimeFrame.Items7")}); + this.comboTimeFrame.Name = "comboTimeFrame"; + this.comboTimeFrame.SelectedIndexChanged += new System.EventHandler(this.comboTimeFrame_SelectedIndexChanged); + // + // buttonApplyTimeFrame + // + resources.ApplyResources(this.buttonApplyTimeFrame, "buttonApplyTimeFrame"); + this.buttonApplyTimeFrame.Name = "buttonApplyTimeFrame"; + this.buttonApplyTimeFrame.UseVisualStyleBackColor = true; + this.buttonApplyTimeFrame.Click += new System.EventHandler(this.buttonApplyTimeFrame_Click); + // + // buttonResetTimeFrame + // + resources.ApplyResources(this.buttonResetTimeFrame, "buttonResetTimeFrame"); + this.buttonResetTimeFrame.Name = "buttonResetTimeFrame"; + this.buttonResetTimeFrame.UseVisualStyleBackColor = true; + this.buttonResetTimeFrame.Click += new System.EventHandler(this.buttonResetTimeFrame_Click); + // // _labelResync // resources.ApplyResources(this._labelResync, "_labelResync"); @@ -179,6 +231,7 @@ this._layout.PerformLayout(); this._layoutMain.ResumeLayout(false); this._layoutMain.PerformLayout(); + this._layoutTimeFrameButtons.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -201,5 +254,10 @@ private System.Windows.Forms.Label _labelResyncOption; private System.Windows.Forms.Label _labelResync; private Controls.KHintButton buttonGAB; + private System.Windows.Forms.Label _labelTimeFrame; + private System.Windows.Forms.ComboBox comboTimeFrame; + private System.Windows.Forms.TableLayoutPanel _layoutTimeFrameButtons; + private System.Windows.Forms.Button buttonApplyTimeFrame; + private System.Windows.Forms.Button buttonResetTimeFrame; } } \ No newline at end of file diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs index bf9ebd7..a27609c 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.cs @@ -1,4 +1,4 @@ -/// Copyright 2017 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, @@ -25,6 +25,7 @@ using System.Windows.Forms; using Acacia.UI; using Acacia.Controls; using Acacia.ZPush; +using Acacia.ZPush.Connect; namespace Acacia.Features.SyncState { @@ -35,7 +36,15 @@ namespace Acacia.Features.SyncState private readonly Button[] _syncButtons; - public SyncStateDialog(FeatureSyncState feature) + private ZPushAccount SelectedAccount + { + get + { + return comboAccounts.SelectedItem as ZPushAccount; + } + } + + public SyncStateDialog(FeatureSyncState feature, ZPushAccount currentAccount) { InitializeComponent(); @@ -50,6 +59,8 @@ namespace Acacia.Features.SyncState // Add the accounts foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts()) comboAccounts.Items.Add(account); + if (currentAccount != null) + comboAccounts.SelectedItem = currentAccount; } private void ShowHint(object sender, KHintButton.HintEventArgs e) @@ -57,12 +68,60 @@ namespace Acacia.Features.SyncState _labelResyncOption.Text = e.Hint ?? string.Empty; } + #region Sync time frame + private void comboAccounts_SelectedIndexChanged(object sender, EventArgs e) { - _syncState = _feature.GetSyncState(comboAccounts.SelectedItem as ZPushAccount); + _syncState = _feature.GetSyncState(SelectedAccount); + _labelTimeFrame.Enabled = comboTimeFrame.Enabled = SelectedAccount != null; + + if (SelectedAccount == null) + comboTimeFrame.SelectedIndex = 0; + else + comboTimeFrame.SelectedIndex = (int)SelectedAccount.SyncTimeFrame; + UpdateUI(); } + private void comboTimeFrame_SelectedIndexChanged(object sender, EventArgs e) + { + CheckTimeFrameDirty(); + } + + private void CheckTimeFrameDirty() + { + if (SelectedAccount != null) + { + SyncTimeFrame timeFrame = (SyncTimeFrame)comboTimeFrame.SelectedIndex; + bool isDirty = timeFrame != SelectedAccount.SyncTimeFrame; + buttonApplyTimeFrame.Enabled = buttonResetTimeFrame.Enabled = isDirty; + } + else + { + buttonApplyTimeFrame.Enabled = buttonResetTimeFrame.Enabled = false; + } + } + + private void buttonResetTimeFrame_Click(object sender, EventArgs e) + { + if (SelectedAccount != null) + comboTimeFrame.SelectedIndex = (int)SelectedAccount.SyncTimeFrame; + } + + private void buttonApplyTimeFrame_Click(object sender, EventArgs e) + { + if (SelectedAccount != null) + { + Busy = true; + + // TODO: do this in the background + _feature.SetDeviceOptions(SelectedAccount, (SyncTimeFrame)comboTimeFrame.SelectedIndex); + CheckTimeFrameDirty(); + } + } + + #endregion + private static readonly string[] OPTION_TEXT = { Properties.Resources.SyncState_Resync_Body_GAB, @@ -150,5 +209,6 @@ namespace Acacia.Features.SyncState progress.Value = 100; } } + } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.resx index a9dc4f6..54b2bbf 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.resx +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/SyncStateDialog.resx @@ -139,13 +139,13 @@ - 5, 711 + 2, 344 - 5, 5, 5, 5 + 2, 2, 2, 2 - 889, 54 + 333, 35 0 @@ -181,13 +181,10 @@ NoControl - 8, 129 - - - 8, 0, 8, 0 + 3, 59 - 203, 60 + 77, 25 5 @@ -217,13 +214,10 @@ Fill - 8, 0 - - - 8, 0, 8, 0 + 3, 0 - 203, 53 + 77, 27 0 @@ -256,16 +250,13 @@ All Z-Push accounts - 227, 7 - - - 8, 7, 8, 7 + 86, 3 - 648, 39 + 242, 21 - 1 + 0 comboAccounts @@ -286,13 +277,10 @@ Fill - 8, 53 - - - 8, 0, 8, 0 + 3, 27 - 203, 76 + 77, 32 2 @@ -319,16 +307,13 @@ Fill - 227, 60 - - - 8, 7, 8, 7 + 86, 30 - 648, 62 + 242, 26 - 3 + 1 progress @@ -349,19 +334,19 @@ Fill - 227, 136 + 86, 62 - 8, 7, 8, 7 + 3, 3, 3, 3 - 8, 7, 8, 7 + 3, 3, 3, 3 - 648, 46 + 242, 19 - 7 + 2 textRemaining @@ -375,6 +360,183 @@ 5 + + True + + + Fill + + + 3, 84 + + + 77, 28 + + + 9 + + + Synchronise + + + MiddleLeft + + + _labelTimeFrame + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutMain + + + 6 + + + True + + + 3 + + + Fill + + + Popup + + + all + + + 1 day + + + 3 days + + + 1 week + + + 2 weeks + + + 1 month + + + 3 months + + + 6 months + + + 3, 3 + + + 102, 21 + + + 0 + + + comboTimeFrame + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutTimeFrameButtons + + + 0 + + + 181, 2 + + + 3, 2, 3, 3 + + + 64, 23 + + + 2 + + + Apply + + + buttonApplyTimeFrame + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutTimeFrameButtons + + + 1 + + + 111, 2 + + + 3, 2, 3, 3 + + + 64, 23 + + + 1 + + + Reset + + + buttonResetTimeFrame + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutTimeFrameButtons + + + 2 + + + Fill + + + 83, 84 + + + 0, 0, 0, 0 + + + 1 + + + 248, 28 + + + 3 + + + _layoutTimeFrameButtons + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + _layoutMain + + + 7 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="comboTimeFrame" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonApplyTimeFrame" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="buttonResetTimeFrame" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,AutoSize,0,AutoSize,0" /><Rows Styles="AutoSize,0" /></TableLayoutSettings> + True @@ -382,13 +544,10 @@ Fill - 8, 189 - - - 8, 0, 8, 0 + 3, 132 - 203, 70 + 77, 35 8 @@ -409,7 +568,7 @@ _layoutMain - 6 + 8 True @@ -427,19 +586,16 @@ NoControl - 227, 196 - - - 8, 7, 8, 7 + 86, 135 - 8, 7, 8, 7 + 3, 3, 3, 3 - 648, 56 + 242, 29 - 0 + 4 Global Address Book @@ -454,7 +610,7 @@ _layoutMain - 7 + 9 True @@ -472,19 +628,16 @@ NoControl - 227, 266 - - - 8, 7, 8, 7 + 86, 170 - 8, 7, 8, 7 + 3, 3, 3, 3 - 648, 56 + 242, 29 - 1 + 5 Signatures @@ -499,7 +652,7 @@ _layoutMain - 8 + 10 True @@ -517,19 +670,16 @@ NoControl - 227, 336 - - - 8, 7, 8, 7 + 86, 205 - 8, 7, 8, 7 + 3, 3, 3, 3 - 648, 56 + 242, 29 - 2 + 6 Server Data @@ -544,7 +694,7 @@ _layoutMain - 9 + 11 True @@ -562,19 +712,16 @@ NoControl - 227, 406 - - - 8, 7, 8, 7 + 86, 240 - 8, 7, 8, 7 + 3, 3, 3, 3 - 648, 56 + 242, 29 - 3 + 7 Full Resynchronisation @@ -589,22 +736,19 @@ _layoutMain - 10 + 12 Fill - 227, 469 - - - 8, 0, 8, 0 + 86, 272 - 0, 14, 0, 0 + 0, 6, 0, 0 - 648, 223 + 242, 64 4 @@ -619,22 +763,19 @@ _layoutMain - 11 + 13 Fill - 8, 7 - - - 8, 7, 8, 7 + 3, 3 - 8 + 11 - 883, 692 + 331, 336 1 @@ -652,7 +793,7 @@ 1 - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelRemaining" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_labelAccount" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboAccounts" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelProgress" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="progress" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="textRemaining" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelResync" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonGAB" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonSignatures" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonServerData" Row="5" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonFullResync" Row="6" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelResyncOption" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Percent,100" /></TableLayoutSettings> + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="_labelRemaining" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_labelAccount" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboAccounts" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelProgress" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="progress" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="textRemaining" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelTimeFrame" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="_layoutTimeFrameButtons" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelResync" Row="6" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="buttonGAB" Row="6" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonSignatures" Row="7" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonServerData" Row="8" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="buttonFullResync" Row="9" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="_labelResyncOption" Row="10" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="AutoSize,0,Percent,100" /><Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Absolute,20,AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0,Percent,100" /></TableLayoutSettings> Fill @@ -660,14 +801,11 @@ 0, 0 - - 8, 7, 8, 7 - 2 - 899, 770 + 337, 381 0 @@ -691,16 +829,13 @@ True - 16, 31 + 6, 13 True - 899, 770 - - - 8, 7, 8, 7 + 337, 381 CenterParent diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs index 4ec7dc8..b09e6b0 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/WebApp/FeatureWebApp.cs @@ -1,6 +1,4 @@ - -using Acacia.Native.MAPI; -/// 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, diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOlkAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOlkAccount.cs index 9b504a3..0117330 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOlkAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/IOlkAccount.cs @@ -8,12 +8,17 @@ using System.Threading.Tasks; namespace Acacia.Native { - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Explicit)] unsafe public struct ACCT_VARIANT { + [FieldOffset(0), MarshalAs(UnmanagedType.U4)] public uint dwType; + [FieldOffset(8)] public char* lpszW; + + [FieldOffset(8), MarshalAs(UnmanagedType.U4)] + public uint dw; } [ComImport] diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs index 2e9d401..cb509b4 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/MAPI/Property.cs @@ -55,6 +55,15 @@ namespace Acacia.Native.MAPI return new SearchQuery.PropertyIdentifier(this); } + public static PropTag FromValue(ushort prop, PropType type) + { + return new PropTag() + { + prop = prop, + type = type + }; + } + public static PropTag FromInt(int v) { return new PropTag() diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs index 480cb8a..133c6d6 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs @@ -1,4 +1,6 @@ -/// Copyright 2016 Kopano b.v. + +using Acacia.Native.MAPI; +/// Copyright 2016 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,7 +15,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using System; using System.Collections.Generic; using System.Linq; @@ -45,9 +46,15 @@ namespace Acacia public const string REG_VAL_REPLY_FORWARD_SIGNATURE = "Reply-Forward Signature"; public const string REG_VAL_CURRENT_SIGNATURE = "KOE Signature Digest"; + public const string REG_VAL_SYNC_TIMEFRAME = "KOE SyncTimeFrame"; + public const string REG_VAL_SYNC_SLIDER = "EAS SyncSlider"; public const string REG_VAL_NEXT_ACCOUNT_ID = "NextAccountID"; public const string REG_VAL_KOE_SHARE_FOR = "KOE Share For"; + public static readonly PropTag PROP_NEW_MESSAGE_SIGNATURE = PropTag.FromValue(0x0016, PropType.UNICODE); + public static readonly PropTag PROP_REPLY_SIGNATURE = PropTag.FromValue(0x0017, PropType.UNICODE); + public static readonly PropTag PROP_SYNC_1_MONTH = PropTag.FromValue(0x2103, PropType.LONG); + #endregion #region PREFIXES diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs index dd29666..9042aaa 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAccount.cs @@ -1,4 +1,6 @@ -/// Copyright 2017 Kopano b.v. + +using Acacia.Native.MAPI; +/// 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,7 +15,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using System; using System.Collections.Generic; using System.Linq; @@ -54,25 +55,8 @@ namespace Acacia.Stubs string BackingFilePath { get; } - // TODO: this is really a Z-Push thing, but it's here to store it in the registry - string LocalSignaturesHash - { - get; - set; - } + string RegistryBaseKey { get; } - string SignatureNewMessage - { - get; - set; - } - - string SignatureReplyForwardMessage - { - get; - set; - } - - string ShareFor {get;} + void SetAccountProp(PropTag prop, object value); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs index 36ef412..8687038 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/OutlookWrappers/AccountWrapper.cs @@ -1,7 +1,5 @@  -using Acacia.Native; -using Acacia.Native.MAPI; -/// Copyright 2017 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, @@ -17,6 +15,8 @@ using Acacia.Native.MAPI; /// /// Consult LICENSE file for details using Acacia.Utils; +using Acacia.Native; +using Acacia.Native.MAPI; using Microsoft.Win32; using System; using System.Collections.Generic; @@ -207,55 +207,6 @@ namespace Acacia.Stubs.OutlookWrappers } } - public string LocalSignaturesHash - { - get - { - return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, null); - } - set - { - RegistryUtil.SetValueString(_regPath, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, value); - } - } - public string SignatureNewMessage - { - get - { - return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_NEW_SIGNATURE, null); - } - set - { - // TODO: constant for account - SetAccountProp(PropTag.FromInt(0x0016001F), value); - } - } - - unsafe private void SetAccountProp(PropTag propTag, string value) - { - // Use IOlkAccount to notify while we're running - // IOlkAccount can only be accessed on main thread - ThisAddIn.Instance.InUI(() => - { - using (ComRelease com = new ComRelease()) - { - NSOutlook.Account account = com.Add(FindAccountObject()); - IOlkAccount olk = com.Add(account.IOlkAccount); - - fixed (char* ptr = value.ToCharArray()) - { - ACCT_VARIANT val = new ACCT_VARIANT() - { - dwType = (uint)PropType.UNICODE, - lpszW = ptr - }; - olk.SetProp(propTag, &val); - olk.SaveChanges(0); - } - } - }); - } - private NSOutlook.Account FindAccountObject() { using (ComRelease com = new ComRelease()) @@ -272,26 +223,50 @@ namespace Acacia.Stubs.OutlookWrappers return null; } - public string SignatureReplyForwardMessage - { - get - { - return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_REPLY_FORWARD_SIGNATURE, null); - } - set - { - SetAccountProp(PropTag.FromInt(0x0017001F), value); - } - } - public string ShareFor + unsafe public void SetAccountProp(PropTag propTag, object value) { - get + // Use IOlkAccount to notify while we're running + // IOlkAccount can only be accessed on main thread + ThisAddIn.Instance.InUI(() => { - return RegistryUtil.GetValueString(_regPath, OutlookConstants.REG_VAL_KOE_SHARE_FOR, null); - } + using (ComRelease com = new ComRelease()) + { + NSOutlook.Account account = com.Add(FindAccountObject()); + IOlkAccount olk = com.Add(account.IOlkAccount); + + switch(propTag.type) + { + case PropType.UNICODE: + fixed (char* ptr = ((string)value).ToCharArray()) + { + ACCT_VARIANT val = new ACCT_VARIANT() + { + dwType = (uint)PropType.UNICODE, + lpszW = ptr + }; + olk.SetProp(propTag, &val); + olk.SaveChanges(0); + } + break; + case PropType.LONG: + { + ACCT_VARIANT val = new ACCT_VARIANT() + { + dwType = (uint)PropType.LONG, + dw = (uint)value + }; + olk.SetProp(propTag, &val); + olk.SaveChanges(0); + break; + } + } + } + }); } #endregion + + public string RegistryBaseKey { get { return _regPath; } } } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs index 4eb4aa2..5718137 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Utils/RegistryUtil.cs @@ -45,6 +45,17 @@ namespace Acacia.Utils Registry.SetValue(keyPath, valueName, value); } + public static int GetValueDword(string keyPath, string valueName, int defaultValue) + { + object o = Registry.GetValue(keyPath, valueName, defaultValue); + return (int)o; + } + + public static void SetValueDword(string keyPath, string valueName, int value) + { + Registry.SetValue(keyPath, valueName, value); + } + public static string RegToString(object o) { if (o is byte[]) diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs index 0e00160..3339a30 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushAccount.cs @@ -1,4 +1,5 @@ -/// 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, @@ -13,7 +14,6 @@ /// along with this program.If not, see. /// /// Consult LICENSE file for details - using Acacia.Stubs; using Acacia.Stubs.OutlookWrappers; using Acacia.Utils; @@ -28,6 +28,9 @@ using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; +using Acacia.Native; +using Acacia.Native.MAPI; +using NSOutlook = Microsoft.Office.Interop.Outlook; namespace Acacia.ZPush { @@ -213,7 +216,10 @@ namespace Acacia.ZPush public string ShareFor { - get { return Account.ShareFor; } + get + { + return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_KOE_SHARE_FOR, null); + } } public string ShareUserName @@ -235,10 +241,10 @@ namespace Acacia.ZPush { get { - if (Account.ShareFor == null) + if (ShareFor == null) return null; - return _zPushAccounts.GetAccount(Account.ShareFor); + return _zPushAccounts.GetAccount(ShareFor); } } @@ -284,5 +290,102 @@ namespace Acacia.ZPush } #endregion + + #region Signatures + + public string LocalSignaturesHash + { + get + { + return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, null); + } + set + { + RegistryUtil.SetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_CURRENT_SIGNATURE, value); + } + } + + public string SignatureNewMessage + { + get + { + return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_NEW_SIGNATURE, null); + } + set + { + Account.SetAccountProp(OutlookConstants.PROP_NEW_MESSAGE_SIGNATURE, value); + } + } + + public string SignatureReplyForwardMessage + { + get + { + return RegistryUtil.GetValueString(Account.RegistryBaseKey, OutlookConstants.REG_VAL_REPLY_FORWARD_SIGNATURE, null); + } + set + { + Account.SetAccountProp(OutlookConstants.PROP_REPLY_SIGNATURE, value); + } + } + + #endregion + + #region Sync time frame + + public SyncTimeFrame SyncTimeFrame + { + get + { + int val = RegistryUtil.GetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_TIMEFRAME, -1); + // Check for default (Outlook) values + if (val < 0) + { + if (EASSyncOneMonth) + return SyncTimeFrame.MONTH_1; + return SyncTimeFrame.ALL; + } + + SyncTimeFrame frame = (SyncTimeFrame)val; + // If the timeframe exceeds one month, but Outlook is set to one month, only one month will be synced. + if (!IsSyncOneMonthOrLess(frame) && EASSyncOneMonth) + return SyncTimeFrame.MONTH_1; + return frame; + } + + set + { + if (value != SyncTimeFrame) + { + // Set the outlook property + EASSyncOneMonth = IsSyncOneMonthOrLess(value); + // And the registry value + RegistryUtil.SetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_TIMEFRAME, (int)value); + } + } + } + + private bool EASSyncOneMonth + { + get + { + return RegistryUtil.GetValueDword(Account.RegistryBaseKey, OutlookConstants.REG_VAL_SYNC_SLIDER, -1) == 1; + } + + set + { + if (value != EASSyncOneMonth) + { + Account.SetAccountProp(OutlookConstants.PROP_SYNC_1_MONTH, value ? (uint)1 : (uint)0); + } + } + } + + private bool IsSyncOneMonthOrLess(SyncTimeFrame sync) + { + return sync <= SyncTimeFrame.MONTH_1 && sync != SyncTimeFrame.ALL; + } + + #endregion } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs index a5bd0ad..1834d23 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/ZPushTypes.cs @@ -132,4 +132,17 @@ namespace Acacia.ZPush #endregion } + + public enum SyncTimeFrame + { + // The order of this is to match the Z-Push settings + ALL, + DAY_1, + DAY_3, + WEEK_1, + WEEK_2, + MONTH_1, + MONTH_3, + MONTH_6 + } }