diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs index 193ded5..79c941b 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.cs @@ -301,6 +301,17 @@ namespace Acacia.Features.SharedFolders textName.Text = value ?? ""; } } + private bool? OptionTrackName + { + get { return textName.Visible ? !_labelName.Enabled : (bool?)null; } + set + { + if (value != null) + { + _labelName.Enabled = !value.Value; + } + } + } private FolderTreeNode _optionNameNode; private CheckState? OptionSendAs @@ -367,6 +378,7 @@ namespace Acacia.Features.SharedFolders _optionSendAsInitial.Clear(); _optionPermissionNodes.Clear(); OptionName = null; + OptionTrackName = null; OptionSendAs = null; OptionPermissions = null; @@ -406,6 +418,7 @@ namespace Acacia.Features.SharedFolders if (_optionNameNode != null && nodes.Length == 1) { OptionName = _optionNameNode.SharedFolder.Name; + OptionTrackName = _optionNameNode.SharedFolder.FlagUpdateShareName; } else { @@ -461,6 +474,10 @@ namespace Acacia.Features.SharedFolders if (_optionNameNode != null) { _optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithName(textName.Text); + + // If the share name matches the folder name, track update + bool track = _optionNameNode.SharedFolder.Name == _optionNameNode.AvailableFolder.DefaultName; + _optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithFlagUpdateShareName(track); } } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs index e478ab0..088e5e0 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/StoreTreeNode.cs @@ -85,7 +85,7 @@ namespace Acacia.Features.SharedFolders internal SharedFolder AddShare(AvailableFolder folder, SharedFolder state) { state = state ?? CreateDefaultShare(folder); - _currentShares[folder.BackendId] = state; + _currentShares[folder.BackendId] = state.PatchInformation(folder); CheckDirty(); return state; } @@ -98,10 +98,6 @@ namespace Acacia.Features.SharedFolders if (folder.IsMailFolder) share = share.WithFlagSendAsOwner(true); - // Default include the store name in root folders - if (folder.ParentId.IsNone) - share = share.WithName(folder.Name + " - " + folder.Store.UserName); - return share; } @@ -118,6 +114,12 @@ namespace Acacia.Features.SharedFolders SharedFolder state; if (_initialShares.TryGetValue(folder.BackendId, out state)) { + // If the folder has been renamed, update if we're tracing it. + if (state.Name != folder.DefaultName) + { + if (state.FlagUpdateShareName) + state = state.WithName(folder.DefaultName); + } return state; } return null; diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs index aec344b..c3411a6 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/AvailableFolder.cs @@ -73,9 +73,23 @@ namespace Acacia.ZPush.API.SharedFolders public SyncId ServerId { get { return _data.ServerId; } } public SyncId ParentId { get { return _data.ParentId; } } + public BackendId ParentIdAsBackend { get { return Parent?.BackendId ?? BackendId.NONE; } } public BackendId BackendId { get { return _data.BackendId; } } public string Name { get { return _data.DisplayName; } } + + public string DefaultName + { + get + { + // Default include the store name in root folders + if (ParentId.IsNone) + return Name + " - " + Store.UserName; + else + return Name; + } + } + public OutlookConstants.SyncType Type { get { return _data.Type; } } public GABUser Store { get; private set; } diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs index b4e2235..3b15cc3 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/SharedFolder.cs @@ -55,13 +55,16 @@ namespace Acacia.ZPush.API.SharedFolders return false; SoapData rhs = (SoapData)o; + // TODO: this isn't really a full equality test, as flags is masked. This is because Equals is only used + // to test if there are changes that need to be applied. It would be nicer to rename this, and + // equals in SharedFolder to something like NeedsApply. return store == rhs.store && folderid == rhs.folderid && parentid == rhs.parentid && name == rhs.name && type == rhs.type && - flags == rhs.flags; + (flags & ShareFlags.Mask_Apply) == (rhs.flags & ShareFlags.Mask_Apply); } public override int GetHashCode() @@ -86,6 +89,17 @@ namespace Acacia.ZPush.API.SharedFolders return _data; } + /// + /// Patches in any information that is available on AvailableFolder, but not SharedFolder. This is specifically the parent id. + /// + public SharedFolder PatchInformation(AvailableFolder folder) + { + if (folder.ParentIdAsBackend != _data.parentid) + { + _data.parentid = folder.ParentIdAsBackend; + } + return this; + } #endregion @@ -100,8 +114,8 @@ namespace Acacia.ZPush.API.SharedFolders { store = folder.Store.UserName, folderid = folder.BackendId, - parentid = folder.Parent?.BackendId ?? BackendId.NONE, - name = folder.Name, + parentid = folder.ParentIdAsBackend, + name = folder.DefaultName, type = OutlookConstants.USER_SYNC_TYPES[(int)folder.Type], flags = folder.IsMailFolder ? ShareFlags.SendAsOwner : ShareFlags.None }; @@ -161,6 +175,7 @@ namespace Acacia.ZPush.API.SharedFolders } public bool FlagSendAsOwner { get { return Flags.HasFlag(ShareFlags.SendAsOwner); } } + public bool FlagUpdateShareName { get { return Flags.HasFlag(ShareFlags.TrackShareName); } } /// /// Returns a copy with the specified 'send as owner' flag. @@ -170,6 +185,14 @@ namespace Acacia.ZPush.API.SharedFolders return WithFlags(value ? (_data.flags | ShareFlags.SendAsOwner) : (_data.flags & ~ShareFlags.SendAsOwner)); } + /// + /// Returns a copy with the specified 'update share name' flag. + /// + public SharedFolder WithFlagUpdateShareName(bool value) + { + return WithFlags(value ? (_data.flags | ShareFlags.TrackShareName) : (_data.flags & ~ShareFlags.TrackShareName)); + } + #endregion #region Standard overrides diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs index e602ce3..b1b7ee0 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/API/SharedFolders/Types.cs @@ -29,7 +29,22 @@ namespace Acacia.ZPush.API.SharedFolders public enum ShareFlags { None = 0, + + /// + /// Mails from folders containing this flag will be sent as the owner of the share, not the user. + /// SendAsOwner = 1, + + /// + /// Folders with this flag will be renamed when the original folder is renamed. + /// + TrackShareName = 2, + + /// + /// The mask indicating which flag changes cause an Apply to become needed. I.e. flags not in the mask + /// are updated only if other changes are made. + /// + Mask_Apply = 1 } /// diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs index eff1718..e02f120 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/Soap/SoapSerializer.cs @@ -169,7 +169,21 @@ namespace Acacia.ZPush.Connect.Soap } private class TypeHandlerInt : TypeHandler { - public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, "int", typeof(long)) { } + public TypeHandlerInt() : base(SoapConstants.XMLNS_XSD, null, typeof(int)) { } + + public override void Serialize(string name, object value, StringBuilder s) + { + s.Append(string.Format("<{0} xsi:type=\"xsd:int\">{1}", name, value)); + } + + protected override object DeserializeContents(XmlNode node, Type expectedType) + { + return long.Parse(node.InnerText); + } + } + private class TypeHandlerLong : TypeHandler + { + public TypeHandlerLong() : base(SoapConstants.XMLNS_XSD, "int", typeof(long)) { } public override void Serialize(string name, object value, StringBuilder s) { @@ -439,6 +453,8 @@ namespace Acacia.ZPush.Connect.Soap static SoapSerializer() { RegisterTypeHandler(new TypeHandlerBoolean()); + // What is called an int in soap might actually be a long here. + RegisterTypeHandler(new TypeHandlerLong()); RegisterTypeHandler(new TypeHandlerInt()); RegisterTypeHandler(new TypeHandlerString()); RegisterTypeHandler(new TypeHandlerList()); diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs index 28ef6f2..e18a406 100644 --- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs +++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/ZPush/Connect/ZPushConnection.cs @@ -130,11 +130,14 @@ namespace Acacia.ZPush.Connect { // Content using (HttpContent content = request.GetContent()) - using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel ?? CancellationToken.None).Result) - using (HttpContent responseContent = response.Content) { - Logger.Instance.Debug(this, "Response: {0}", responseContent.ReadAsStringAsync().Result); - return request.ParseResponse(responseContent.ReadAsStreamAsync().Result); + Logger.Instance.Trace(this, "Request: {0}", content.ReadAsStringAsync().Result); + using (HttpResponseMessage response = _client.PostAsync(url, content, _cancel ?? CancellationToken.None).Result) + using (HttpContent responseContent = response.Content) + { + Logger.Instance.Trace(this, "Response: {0}", responseContent.ReadAsStringAsync().Result); + return request.ParseResponse(responseContent.ReadAsStreamAsync().Result); + } } } }