[KOE-12] Basic implementation of reminder query modification. For now only works when existing shares are modified, as the new shares do not have a sync id yet. This will be added.

Added SharedFoldersManager as a wrapper around the API; it manages the API and syncing with the reminder query.
Also untested on 32-bit for now, which will most likely crash, as the COM interface has some size-specific fields.
This commit is contained in:
Patrick Simpson 2017-02-28 12:14:13 +01:00
parent 65912b962c
commit 43e0d9b02d
14 changed files with 557 additions and 220 deletions

View File

@ -274,7 +274,8 @@
</Compile>
<Compile Include="Features\SendAs\FeatureSendAs.cs" />
<Compile Include="Features\SharedFolders\FolderTreeNode.cs" />
<Compile Include="Features\SharedFolders\SharedCalendarReminders.cs" />
<Compile Include="Features\SharedFolders\RemindersQuery.cs" />
<Compile Include="Features\SharedFolders\SharedFoldersManager.cs" />
<Compile Include="Features\Signatures\FeatureSignatures.cs" />
<Compile Include="Features\Signatures\SignaturesSettings.cs">
<SubType>UserControl</SubType>

View File

@ -58,7 +58,7 @@ namespace Acacia.Features.SharedFolders
ZPushAccount account = Watcher.Accounts.GetAccount(folder);
if (account != null)
{
new SharedFoldersDialog(account, folder.SyncId).ShowDialog();
new SharedFoldersDialog(this, account, folder.SyncId).ShowDialog();
}
}
@ -67,12 +67,21 @@ namespace Acacia.Features.SharedFolders
ZPushAccount account = Watcher.CurrentZPushAccount();
if (account != null)
{
new SharedFoldersDialog(account).ShowDialog();
new SharedFoldersDialog(this, account).ShowDialog();
}
}
#endregion
#region Folder management
internal SharedFoldersManager Manage(ZPushAccount account)
{
return new SharedFoldersManager(this, account);
}
#endregion
#region Shared folders sync
private const string KEY_SHARES = "Shares";

View File

@ -0,0 +1,161 @@
using Acacia.Native.MAPI;
using Acacia.Stubs;
using Acacia.Utils;
using Acacia.ZPush;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acacia.Features.SharedFolders
{
public class RemindersQuery : DisposableWrapper, LogContext
{
private static readonly SearchQuery.PropertyIdentifier PROP_FOLDER = new SearchQuery.PropertyIdentifier(PropTag.FromInt(0x6B20001F));
private readonly LogContext _context;
private readonly IFolder _folder;
private SearchQuery _queryRoot;
private SearchQuery.Or _queryCustom;
public RemindersQuery(LogContext context, IStore store)
{
this._context = context;
_folder = store.GetSpecialFolder(SpecialFolder.Reminders);
}
public bool Open()
{
if (_queryCustom != null)
return true;
try
{
_queryRoot = _folder.SearchCriteria;
if (!(_queryRoot is SearchQuery.And))
return false;
Logger.Instance.Trace(this, "Current query1: {0}", _queryRoot.ToString());
SearchQuery.And root = (SearchQuery.And)_queryRoot;
// TODO: more strict checking of query
if (root.Operands.Count == 3)
{
this._queryCustom = root.Operands.ElementAt(2) as SearchQuery.Or;
if (this._queryCustom != null)
{
// TODO: check property test
return true;
}
}
// We have the root, but not the custom query. Create it.
Logger.Instance.Debug(this, "Creating custom query");
Logger.Instance.Trace(this, "Current query: {0}", root.ToString());
_queryCustom = new SearchQuery.Or();
// Add the prefix exclusion for shared folders
_queryCustom.Add(
new SearchQuery.Not(
new SearchQuery.PropertyContent(
PROP_FOLDER, SearchQuery.ContentMatchOperation.Prefix, SearchQuery.ContentMatchModifiers.None, "S"
)
)
);
root.Operands.Add(_queryCustom);
Logger.Instance.Trace(this, "Modified query: {0}", root.ToString());
// Store it
// TODO: could store it on change only
_folder.SearchCriteria = root;
Logger.Instance.Trace(this, "Modified query2: {0}", _folder.SearchCriteria.ToString());
}
catch (Exception e)
{
Logger.Instance.Error(this, "Exception in Open: {0}", e);
}
return _queryCustom != null;
}
public string LogContextId
{
get
{
return _context.LogContextId;
}
}
protected override void DoRelease()
{
_folder.Dispose();
}
public void Commit()
{
_folder.SearchCriteria = _queryRoot;
}
public void UpdateReminders(SyncId folderId, bool wantReminders)
{
Logger.Instance.Trace(this, "Setting reminders for folder {0}: {1}", wantReminders, folderId);
string prefix = MakeFolderPrefix(folderId);
// Find existing
for (int i = 0; i < _queryCustom.Operands.Count;)
{
SearchQuery.PropertyContent element = _queryCustom.Operands[i] as SearchQuery.PropertyContent;
if (element != null && prefix == (string)element.Content)
{
Logger.Instance.Trace(this, "Found at {0}: {1}", i, folderId);
// Found it. If we want reminders, we're done
if (wantReminders)
return;
// Otherwise remove it. Still continue looking for others, just in case of duplicates
_queryCustom.Operands.RemoveAt(i);
}
else ++i;
}
// Not found, add if wanted
if (wantReminders)
{
Logger.Instance.Trace(this, "Adding reminders for {0}", folderId);
_queryCustom.Operands.Add(new SearchQuery.PropertyContent(
PROP_FOLDER, SearchQuery.ContentMatchOperation.Prefix, SearchQuery.ContentMatchModifiers.None, prefix
));
}
}
public void RemoveStaleReminders(IEnumerable<SyncId> wanted)
{
// Collect the valid prefixes
HashSet<string> prefixes = new HashSet<string>();
foreach (SyncId id in wanted)
prefixes.Add(MakeFolderPrefix(id));
// Remove all operands for which we do not want the prefix
for (int i = 0; i < _queryCustom.Operands.Count;)
{
SearchQuery.PropertyContent element = _queryCustom.Operands[i] as SearchQuery.PropertyContent;
if (element != null)
{
string prefix = (string)element.Content;
if (prefixes.Contains(prefix))
{
++i;
continue;
}
Logger.Instance.Trace(this, "Unwanted prefix at {0}: {1}", i, prefix);
_queryCustom.Operands.RemoveAt(i);
}
else ++i;
}
}
private string MakeFolderPrefix(SyncId folderId)
{
return folderId.ToString() + ":";
}
}
}

View File

@ -1,80 +0,0 @@
using Acacia.Native.MAPI;
using Acacia.Stubs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Acacia.Features.SharedFolders
{
public class SharedCalendarReminders : LogContext
{
private static readonly SearchQuery.PropertyIdentifier PROP_FOLDER = new SearchQuery.PropertyIdentifier(PropTag.FromInt(0x6B20001F));
private readonly LogContext _context;
public string LogContextId
{
get
{
return _context.LogContextId;
}
}
public SharedCalendarReminders(LogContext context)
{
this._context = context;
}
public void Initialise(IStore store)
{
using (IFolder reminders = store.GetSpecialFolder(SpecialFolder.Reminders))
{
SearchQuery.Or custom = FindCustomQuery(reminders, true);
}
}
private SearchQuery.Or FindCustomQuery(IFolder reminders, bool addIfNeeded)
{
SearchQuery query = reminders.SearchCriteria;
if (!(query is SearchQuery.And))
return null;
Logger.Instance.Trace(this, "Current query1: {0}", query.ToString());
SearchQuery.And root = (SearchQuery.And)query;
// TODO: more strict checking of query
if (root.Operands.Count == 3)
{
SearchQuery.Or custom = root.Operands.ElementAt(2) as SearchQuery.Or;
if (custom != null)
{
// TODO: check property test
return custom;
}
}
// We have the root, but not the custom query. Create it if needed.
if (addIfNeeded)
{
Logger.Instance.Debug(this, "Creating custom query");
Logger.Instance.Trace(this, "Current query: {0}", root.ToString());
SearchQuery.Or custom = new SearchQuery.Or();
// Add the prefix exclusion for shared folders
custom.Add(
new SearchQuery.Not(
new SearchQuery.PropertyContent(
PROP_FOLDER, SearchQuery.ContentMatchOperation.Prefix, SearchQuery.ContentMatchModifiers.None, "S"
)
)
);
root.Operands.Add(custom);
Logger.Instance.Trace(this, "Modified query: {0}", root.ToString());
reminders.SearchCriteria = root;
Logger.Instance.Trace(this, "Modified query2: {0}", reminders.SearchCriteria.ToString());
}
return null;
}
}
}

View File

@ -47,6 +47,8 @@
this._labelPermissions = new System.Windows.Forms.Label();
this.labelPermissionsValue = new System.Windows.Forms.Label();
this.dialogButtons = new Acacia.Controls.KDialogButtons();
this._labelReminders = new System.Windows.Forms.Label();
this.checkReminders = new System.Windows.Forms.CheckBox();
this._layout.SuspendLayout();
this._mainBusyHider.SuspendLayout();
this._layoutMain.SuspendLayout();
@ -137,8 +139,10 @@
this._layoutOptions.Controls.Add(this.textName, 1, 0);
this._layoutOptions.Controls.Add(this._labelSendAs, 0, 1);
this._layoutOptions.Controls.Add(this.checkSendAs, 1, 1);
this._layoutOptions.Controls.Add(this._labelPermissions, 0, 2);
this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 2);
this._layoutOptions.Controls.Add(this._labelPermissions, 0, 3);
this._layoutOptions.Controls.Add(this.labelPermissionsValue, 1, 3);
this._layoutOptions.Controls.Add(this._labelReminders, 0, 2);
this._layoutOptions.Controls.Add(this.checkReminders, 1, 2);
this._layoutOptions.Name = "_layoutOptions";
//
// _labelName
@ -185,6 +189,18 @@
this.dialogButtons.Name = "dialogButtons";
this.dialogButtons.Apply += new System.EventHandler(this.dialogButtons_Apply);
//
// _labelReminders
//
resources.ApplyResources(this._labelReminders, "_labelReminders");
this._labelReminders.Name = "_labelReminders";
//
// checkReminders
//
resources.ApplyResources(this.checkReminders, "checkReminders");
this.checkReminders.Name = "checkReminders";
this.checkReminders.UseVisualStyleBackColor = true;
this.checkReminders.CheckedChanged += new System.EventHandler(this.checkReminders_CheckedChanged);
//
// SharedFoldersDialog
//
resources.ApplyResources(this, "$this");
@ -228,5 +244,7 @@
private Controls.KDialogButtons dialogButtons;
private System.Windows.Forms.TableLayoutPanel _layoutCenterGABLookup;
private UI.GABLookupControl gabLookup;
private System.Windows.Forms.Label _labelReminders;
private System.Windows.Forms.CheckBox checkReminders;
}
}

View File

@ -16,10 +16,8 @@
using Acacia.Controls;
using Acacia.Features.GAB;
using Acacia.Stubs;
using Acacia.UI;
using Acacia.UI.Outlook;
using Acacia.Utils;
using Acacia.ZPush;
using Acacia.ZPush.API.SharedFolders;
using System;
@ -34,21 +32,20 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using static Acacia.ZPush.API.SharedFolders.SharedFoldersAPI;
namespace Acacia.Features.SharedFolders
{
public partial class SharedFoldersDialog : KDialogNew
{
private readonly ZPushAccount _account;
private SyncId _initialSyncId;
private readonly SharedFoldersManager _folders;
private readonly SyncId _initialSyncId;
private SharedFolder _initialFolder;
public SharedFoldersDialog(ZPushAccount account, SyncId initial = null)
public SharedFoldersDialog(FeatureSharedFolders feature, ZPushAccount account, SyncId initial = null)
{
this._account = account;
this._folders = feature.Manage(account);
this._initialSyncId = initial;
InitializeComponent();
@ -77,7 +74,7 @@ namespace Acacia.Features.SharedFolders
ShowOptions(new KTreeNode[0]);
// Set up user selector
gabLookup.GAB = FeatureGAB.FindGABForAccount(_account);
gabLookup.GAB = FeatureGAB.FindGABForAccount(account);
}
#region Load and store
@ -88,21 +85,18 @@ namespace Acacia.Features.SharedFolders
KUITask
.New((ctx) =>
{
using (SharedFoldersAPI api = new SharedFoldersAPI(_account))
{
// TODO: bind cancellation token to Cancel button
// Fetch current shares
ICollection<SharedFolder> folders = api.GetCurrentShares(ctx.CancellationToken);
// TODO: bind cancellation token to Cancel button
// Fetch current shares
ICollection<SharedFolder> folders = _folders.GetCurrentShares(ctx.CancellationToken);
// Find the initial folder if required
if (_initialSyncId != null)
_initialFolder = folders.FirstOrDefault(f => f.SyncId == _initialSyncId);
// Find the initial folder if required
if (_initialSyncId != null)
_initialFolder = folders.FirstOrDefault(f => f.SyncId == _initialSyncId);
// Group by store and folder id
return folders.GroupBy(f => f.Store)
.ToDictionary(group => group.Key,
group => group.ToDictionary(folder => folder.BackendId));
}
// Group by store and folder id
return folders.GroupBy(f => f.Store)
.ToDictionary(group => group.Key,
group => group.ToDictionary(folder => folder.BackendId));
})
.OnSuccess(InitialiseTree, true)
.OnError((e) =>
@ -163,27 +157,25 @@ namespace Acacia.Features.SharedFolders
BusyText = Properties.Resources.SharedFolders_Applying_Label;
KUITask.New((ctx) =>
{
using (SharedFoldersAPI folders = new SharedFoldersAPI(_account))
// We reuse the same busy indicationg for all calls. A count is kept to ensure it's removed.
int count = 0;
foreach (StoreTreeNode storeNode in _userFolders.Values)
{
// We reuse the same busy indicationg for all calls. A count is kept to ensure it's removed.
int count = 0;
foreach (StoreTreeNode storeNode in _userFolders.Values)
if (storeNode.IsDirty)
{
if (storeNode.IsDirty)
{
ctx.AddBusy(1);
++count;
ctx.AddBusy(1);
++count;
folders.SetCurrentShares(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken);
}
_folders.SetSharesForStore(storeNode.User, storeNode.CurrentShares, ctx.CancellationToken);
}
return count;
}
return count;
})
.OnSuccess((ctx, count) =>
{
// Update UI state
foreach (StoreTreeNode storeNode in _userFolders.Values)
if (storeNode.IsDirty)
storeNode.ChangesApplied();
@ -255,7 +247,7 @@ namespace Acacia.Features.SharedFolders
}
// Add the node
node = new StoreTreeNode(_account, user, user.DisplayName, currentShares ?? new Dictionary<BackendId, SharedFolder>());
node = new StoreTreeNode(_folders, user, user.DisplayName, currentShares ?? new Dictionary<BackendId, SharedFolder>());
node.DirtyChanged += UserSharesChanged;
_userFolders.Add(user, node);
kTreeFolders.RootNodes.Add(node);
@ -333,6 +325,25 @@ namespace Acacia.Features.SharedFolders
private readonly List<FolderTreeNode> _optionSendAsNodes = new List<FolderTreeNode>();
private readonly List<bool> _optionSendAsInitial = new List<bool>();
private CheckState? OptionReminders
{
get
{
if (checkReminders.Visible)
return checkReminders.CheckState;
return null;
}
set
{
_labelReminders.Visible = checkReminders.Visible = value != null;
if (value != null)
checkReminders.CheckState = value.Value;
}
}
private readonly List<FolderTreeNode> _optionRemindersNodes = new List<FolderTreeNode>();
private readonly List<bool> _optionRemindersInitial = new List<bool>();
private Permission? _optionPermissions;
private Permission? OptionPermissions
{
@ -376,10 +387,13 @@ namespace Acacia.Features.SharedFolders
_optionNameNode = null;
_optionSendAsNodes.Clear();
_optionSendAsInitial.Clear();
_optionRemindersNodes.Clear();
_optionRemindersInitial.Clear();
_optionPermissionNodes.Clear();
OptionName = null;
OptionTrackName = null;
OptionSendAs = null;
OptionReminders = null;
OptionPermissions = null;
foreach (KTreeNode node in nodes)
@ -399,12 +413,18 @@ namespace Acacia.Features.SharedFolders
// Assume we will edit the name for this node; cleared below if there are multiple
_optionNameNode = folderNode;
// Show send as if there are any mail folders
if (folder.IsMailFolder)
if (folder.Type.IsMail())
{
// Show send as if there are any mail folders
_optionSendAsNodes.Add(folderNode);
_optionSendAsInitial.Add(folderNode.SharedFolder.FlagSendAsOwner);
}
else if (folder.Type.IsAppointment())
{
// Show reminders for appointment folders
_optionRemindersNodes.Add(folderNode);
_optionRemindersInitial.Add(folderNode.SharedFolder.FlagCalendarReminders);
}
// Show permissions for all shared nodes
_optionPermissionNodes.Add(folderNode);
@ -448,6 +468,21 @@ namespace Acacia.Features.SharedFolders
checkSendAs.ThreeState = true;
}
}
// Reminders shown if any node supports it
if (_optionRemindersNodes.Count > 0)
{
bool reminders = _optionRemindersNodes.First().SharedFolder.FlagCalendarReminders;
if (_optionRemindersNodes.All(x => x.SharedFolder.FlagCalendarReminders == reminders))
{
OptionReminders = reminders ? CheckState.Checked : CheckState.Unchecked;
checkReminders.ThreeState = false;
}
else
{
OptionReminders = CheckState.Indeterminate;
checkReminders.ThreeState = true;
}
}
}
finally
{
@ -477,7 +512,7 @@ namespace Acacia.Features.SharedFolders
// If the share name matches the folder name, track update
bool track = _optionNameNode.SharedFolder.Name == _optionNameNode.AvailableFolder.DefaultName;
_optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithFlagUpdateShareName(track);
_optionNameNode.SharedFolder = _optionNameNode.SharedFolder.WithFlagTrackShareName(track);
}
}
@ -507,6 +542,26 @@ namespace Acacia.Features.SharedFolders
}
}
private void checkReminders_CheckedChanged(object sender, EventArgs e)
{
for (int i = 0; i < _optionRemindersNodes.Count; ++i)
{
FolderTreeNode node = _optionRemindersNodes[i];
bool reminders = false;
switch (checkReminders.CheckState)
{
case CheckState.Checked: reminders = true; break;
case CheckState.Indeterminate: reminders = _optionRemindersInitial[i]; break;
case CheckState.Unchecked: reminders = false; break;
}
if (node.SharedFolder.FlagCalendarReminders != reminders)
{
node.SharedFolder = node.SharedFolder.WithFlagCalendarReminders(reminders);
}
}
}
#endregion
}
}

View File

@ -145,13 +145,10 @@
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="labelSelectUser.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 0</value>
</data>
<data name="labelSelectUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 0, 4, 0</value>
<value>3, 0</value>
</data>
<data name="labelSelectUser.Size" type="System.Drawing.Size, System.Drawing">
<value>143, 36</value>
<value>105, 31</value>
</data>
<data name="labelSelectUser.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
@ -190,16 +187,13 @@
<value>NoControl</value>
</data>
<data name="buttonOpenUser.Location" type="System.Drawing.Point, System.Drawing">
<value>510, 4</value>
</data>
<data name="buttonOpenUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
<value>380, 3</value>
</data>
<data name="buttonOpenUser.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>11, 0, 11, 0</value>
<value>8, 0, 8, 0</value>
</data>
<data name="buttonOpenUser.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 28</value>
<value>59, 25</value>
</data>
<data name="buttonOpenUser.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -232,16 +226,13 @@
<value>Popup</value>
</data>
<data name="gabLookup.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 4</value>
</data>
<data name="gabLookup.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
<value>3, 3</value>
</data>
<data name="gabLookup.MinimumSize" type="System.Drawing.Size, System.Drawing">
<value>265, 0</value>
<value>200, 0</value>
</data>
<data name="gabLookup.Size" type="System.Drawing.Size, System.Drawing">
<value>343, 24</value>
<value>256, 21</value>
</data>
<data name="gabLookup.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -262,7 +253,7 @@
<value>Fill</value>
</data>
<data name="_layoutCenterGABLookup.Location" type="System.Drawing.Point, System.Drawing">
<value>153, 2</value>
<value>113, 2</value>
</data>
<data name="_layoutCenterGABLookup.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 2, 2, 2</value>
@ -271,7 +262,7 @@
<value>3</value>
</data>
<data name="_layoutCenterGABLookup.Size" type="System.Drawing.Size, System.Drawing">
<value>351, 32</value>
<value>262, 27</value>
</data>
<data name="_layoutCenterGABLookup.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
@ -295,16 +286,13 @@
<value>Fill</value>
</data>
<data name="_layoutSelectUser.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 4</value>
</data>
<data name="_layoutSelectUser.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
<value>3, 3</value>
</data>
<data name="_layoutSelectUser.RowCount" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="_layoutSelectUser.Size" type="System.Drawing.Size, System.Drawing">
<value>589, 36</value>
<value>442, 31</value>
</data>
<data name="_layoutSelectUser.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
@ -322,19 +310,16 @@
<value>0</value>
</data>
<data name="_layoutSelectUser.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /&gt;&lt;Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /&gt;&lt;Rows Styles="Percent,100,Absolute,37" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="labelSelectUser" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="buttonOpenUser" Row="0" RowSpan="1" Column="2" ColumnSpan="1" /&gt;&lt;Control Name="_layoutCenterGABLookup" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100,AutoSize,0" /&gt;&lt;Rows Styles="Percent,100,Absolute,27" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="kTreeFolders.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="kTreeFolders.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 48</value>
</data>
<data name="kTreeFolders.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
<value>3, 40</value>
</data>
<data name="kTreeFolders.Size" type="System.Drawing.Size, System.Drawing">
<value>589, 377</value>
<value>442, 275</value>
</data>
<data name="kTreeFolders.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -367,13 +352,10 @@
<value>Fill</value>
</data>
<data name="_labelName.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 0</value>
</data>
<data name="_labelName.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 0, 4, 0</value>
<value>3, 0</value>
</data>
<data name="_labelName.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 30</value>
<value>82, 26</value>
</data>
<data name="_labelName.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
@ -400,13 +382,13 @@
<value>Fill</value>
</data>
<data name="textName.Location" type="System.Drawing.Point, System.Drawing">
<value>118, 4</value>
<value>94, 3</value>
</data>
<data name="textName.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>8, 4, 4, 4</value>
<value>6, 3, 3, 3</value>
</data>
<data name="textName.Size" type="System.Drawing.Size, System.Drawing">
<value>475, 22</value>
<value>351, 20</value>
</data>
<data name="textName.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
@ -430,13 +412,10 @@
<value>Fill</value>
</data>
<data name="_labelSendAs.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 30</value>
</data>
<data name="_labelSendAs.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 0, 4, 0</value>
<value>3, 26</value>
</data>
<data name="_labelSendAs.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 34</value>
<value>82, 27</value>
</data>
<data name="_labelSendAs.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
@ -466,16 +445,16 @@
<value>Left</value>
</data>
<data name="checkSendAs.Location" type="System.Drawing.Point, System.Drawing">
<value>118, 35</value>
<value>94, 30</value>
</data>
<data name="checkSendAs.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>8, 5, 4, 4</value>
<value>6, 4, 3, 3</value>
</data>
<data name="checkSendAs.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 4, 0, 4</value>
<value>0, 3, 0, 3</value>
</data>
<data name="checkSendAs.Size" type="System.Drawing.Size, System.Drawing">
<value>18, 25</value>
<value>15, 20</value>
</data>
<data name="checkSendAs.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
@ -499,16 +478,13 @@
<value>Fill</value>
</data>
<data name="_labelPermissions.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 64</value>
</data>
<data name="_labelPermissions.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 0, 4, 0</value>
<value>3, 80</value>
</data>
<data name="_labelPermissions.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 5, 0, 4</value>
<value>0, 4, 0, 3</value>
</data>
<data name="_labelPermissions.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 26</value>
<value>82, 20</value>
</data>
<data name="_labelPermissions.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
@ -541,16 +517,13 @@
<value>MiddleLeft</value>
</data>
<data name="labelPermissionsValue.Location" type="System.Drawing.Point, System.Drawing">
<value>114, 64</value>
</data>
<data name="labelPermissionsValue.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 0, 4, 0</value>
<value>91, 80</value>
</data>
<data name="labelPermissionsValue.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 5, 0, 4</value>
<value>0, 4, 0, 3</value>
</data>
<data name="labelPermissionsValue.Size" type="System.Drawing.Size, System.Drawing">
<value>479, 26</value>
<value>354, 20</value>
</data>
<data name="labelPermissionsValue.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
@ -573,20 +546,86 @@
<data name="&gt;&gt;labelPermissionsValue.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<data name="_labelReminders.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="_labelReminders.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="_labelReminders.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 53</value>
</data>
<data name="_labelReminders.Size" type="System.Drawing.Size, System.Drawing">
<value>82, 27</value>
</data>
<data name="_labelReminders.TabIndex" type="System.Int32, mscorlib">
<value>6</value>
</data>
<data name="_labelReminders.Text" xml:space="preserve">
<value>Show reminders</value>
</data>
<data name="_labelReminders.TextAlign" type="System.Drawing.ContentAlignment, System.Drawing">
<value>MiddleLeft</value>
</data>
<data name="&gt;&gt;_labelReminders.Name" xml:space="preserve">
<value>_labelReminders</value>
</data>
<data name="&gt;&gt;_labelReminders.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;_labelReminders.Parent" xml:space="preserve">
<value>_layoutOptions</value>
</data>
<data name="&gt;&gt;_labelReminders.ZOrder" xml:space="preserve">
<value>6</value>
</data>
<data name="checkReminders.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="checkReminders.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Left</value>
</data>
<data name="checkReminders.Location" type="System.Drawing.Point, System.Drawing">
<value>94, 57</value>
</data>
<data name="checkReminders.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 4, 3, 3</value>
</data>
<data name="checkReminders.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 3, 0, 3</value>
</data>
<data name="checkReminders.Size" type="System.Drawing.Size, System.Drawing">
<value>15, 20</value>
</data>
<data name="checkReminders.TabIndex" type="System.Int32, mscorlib">
<value>7</value>
</data>
<data name="&gt;&gt;checkReminders.Name" xml:space="preserve">
<value>checkReminders</value>
</data>
<data name="&gt;&gt;checkReminders.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;checkReminders.Parent" xml:space="preserve">
<value>_layoutOptions</value>
</data>
<data name="&gt;&gt;checkReminders.ZOrder" xml:space="preserve">
<value>7</value>
</data>
<data name="_layoutOptions.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="_layoutOptions.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 429</value>
<value>0, 318</value>
</data>
<data name="_layoutOptions.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 0, 0, 0</value>
</data>
<data name="_layoutOptions.RowCount" type="System.Int32, mscorlib">
<value>3</value>
<value>4</value>
</data>
<data name="_layoutOptions.Size" type="System.Drawing.Size, System.Drawing">
<value>597, 90</value>
<value>448, 100</value>
</data>
<data name="_layoutOptions.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
@ -604,7 +643,7 @@
<value>2</value>
</data>
<data name="_layoutOptions.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="_labelPermissions" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="labelPermissionsValue" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100" /&gt;&lt;Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="_labelName" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="textName" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="_labelSendAs" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="checkSendAs" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="_labelPermissions" Row="3" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="labelPermissionsValue" Row="3" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;Control Name="_labelReminders" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="checkReminders" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="AutoSize,0,Percent,100" /&gt;&lt;Rows Styles="AutoSize,0,AutoSize,0,AutoSize,0,AutoSize,0" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="_layoutMain.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
@ -612,14 +651,11 @@
<data name="_layoutMain.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="_layoutMain.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
</data>
<data name="_layoutMain.RowCount" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="_layoutMain.Size" type="System.Drawing.Size, System.Drawing">
<value>597, 519</value>
<value>448, 418</value>
</data>
<data name="_layoutMain.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
@ -643,13 +679,10 @@
<value>Fill</value>
</data>
<data name="_mainBusyHider.Location" type="System.Drawing.Point, System.Drawing">
<value>4, 4</value>
</data>
<data name="_mainBusyHider.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
<value>3, 3</value>
</data>
<data name="_mainBusyHider.Size" type="System.Drawing.Size, System.Drawing">
<value>597, 519</value>
<value>448, 418</value>
</data>
<data name="_mainBusyHider.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
@ -679,13 +712,13 @@
<value>Fill</value>
</data>
<data name="dialogButtons.Location" type="System.Drawing.Point, System.Drawing">
<value>2, 528</value>
<value>2, 425</value>
</data>
<data name="dialogButtons.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 1, 2, 1</value>
</data>
<data name="dialogButtons.Size" type="System.Drawing.Size, System.Drawing">
<value>601, 39</value>
<value>450, 35</value>
</data>
<data name="dialogButtons.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
@ -706,7 +739,7 @@
<value>Fill</value>
</data>
<data name="_layout.Location" type="System.Drawing.Point, System.Drawing">
<value>8, 7</value>
<value>6, 6</value>
</data>
<data name="_layout.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>0, 0, 0, 0</value>
@ -715,7 +748,7 @@
<value>2</value>
</data>
<data name="_layout.Size" type="System.Drawing.Size, System.Drawing">
<value>605, 568</value>
<value>454, 461</value>
</data>
<data name="_layout.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
@ -733,19 +766,22 @@
<value>0</value>
</data>
<data name="_layout.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="_mainBusyHider" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="dialogButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="Percent,100" /&gt;&lt;Rows Styles="Percent,100,AutoSize,0,Absolute,25" /&gt;&lt;/TableLayoutSettings&gt;</value>
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="_mainBusyHider" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="dialogButtons" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="Percent,100" /&gt;&lt;Rows Styles="Percent,100,AutoSize,0,Absolute,20" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>8, 16</value>
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>621, 582</value>
<value>466, 473</value>
</data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 2, 2, 2</value>
</data>
<data name="$this.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>8, 7, 8, 7</value>
<value>6, 6, 6, 6</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterParent</value>

View File

@ -0,0 +1,122 @@
using Acacia.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Acacia.ZPush;
using Acacia.ZPush.API.SharedFolders;
using System.Threading;
using Acacia.Native.MAPI;
namespace Acacia.Features.SharedFolders
{
/// <summary>
/// Manages changes to shared folders.
/// </summary>
public class SharedFoldersManager : DisposableWrapper
{
/// <summary>
/// Contains 'folderid:itemid'. The folder id is used to detect shared folders.
/// TODO: put this in a shared lib somewhere
/// </summary>
private static readonly SearchQuery.PropertyIdentifier PROP_AS_ITEMID = new SearchQuery.PropertyIdentifier(PropTag.FromInt(0x6B20001F));
private readonly ZPushAccount _account;
private readonly FeatureSharedFolders _feature;
private readonly SharedFoldersAPI _api;
private RemindersQuery _query;
public SharedFoldersManager(FeatureSharedFolders featureSharedFolders, ZPushAccount account)
{
this._feature = featureSharedFolders;
this._account = account;
_api = new SharedFoldersAPI(account);
}
protected override void DoRelease()
{
_api.Dispose();
if (_query != null)
_query.Dispose();
}
#region API
/// <summary>
/// Sets all shares for the specified store.
/// </summary>
public void SetSharesForStore(GABUser store, ICollection<SharedFolder> shares, CancellationToken? cancel)
{
// Make sure reminders are updated as soon as possible
UpdateReminders(shares);
_api.SetCurrentShares(store, shares, cancel);
// Commit changes
if (_query != null)
_query.Commit();
}
public ICollection<SharedFolder> GetCurrentShares(CancellationToken? cancel)
{
// Fetch the shares
ICollection<SharedFolder> shares = _api.GetCurrentShares(cancel);
// Make sure reminders are disabled as soon as possible
UpdateReminders(shares);
// Remove any reminders from the shares that are not wanted, they are stale
OpenQuery()?.RemoveStaleReminders(
shares
.Where(x => x.IsSynced && x.SyncType.IsAppointment() && x.FlagCalendarReminders)
.Select(x => x.SyncId)
);
// Commit changes
if (_query != null)
_query.Commit();
return shares;
}
public ICollection<AvailableFolder> GetStoreFolders(GABUser store)
{
return _api.GetUserFolders(store);
}
#endregion
#region Reminders
private void UpdateReminders(ICollection<SharedFolder> shares)
{
foreach(SharedFolder share in shares)
{
Logger.Instance.Debug(this, "UpdateReminders: {0}", share);
if (share.IsSynced && share.SyncType.IsAppointment())
{
OpenQuery()?.UpdateReminders(share.SyncId, share.FlagCalendarReminders);
}
}
}
private RemindersQuery OpenQuery()
{
if (_query == null)
{
RemindersQuery query = new RemindersQuery(_feature, _account.Account.Store);
if (query.Open())
{
_query = query;
}
else
{
query.Dispose();
}
}
return _query;
}
#endregion
}
}

View File

@ -41,7 +41,7 @@ namespace Acacia.Features.SharedFolders
private readonly Dictionary<BackendId, SharedFolder> _initialShares;
private readonly Dictionary<BackendId, SharedFolder> _currentShares;
public StoreTreeNode(ZPushAccount account, GABUser user, string text, Dictionary<BackendId, SharedFolder> currentFolders)
public StoreTreeNode(SharedFoldersManager folders, GABUser user, string text, Dictionary<BackendId, SharedFolder> currentFolders)
:
base(text)
{
@ -51,7 +51,7 @@ namespace Acacia.Features.SharedFolders
// cleaning up automatically any obsolote shares.
this._currentShares = new Dictionary<BackendId, SharedFolder>();
ChildLoader = new UserFolderLoader(this, account, user);
ChildLoader = new UserFolderLoader(this, folders, user);
ChildLoader.ReloadOnCloseOpen = true;
HasCheckBox = false;
@ -95,7 +95,7 @@ namespace Acacia.Features.SharedFolders
SharedFolder share = new SharedFolder(folder);
// Default send as for mail folders
if (folder.IsMailFolder)
if (folder.Type.IsMail())
share = share.WithFlagSendAsOwner(true);
return share;
@ -167,21 +167,18 @@ namespace Acacia.Features.SharedFolders
public class UserFolderLoader : KTreeNodeLoader
{
private readonly ZPushAccount _account;
private readonly SharedFoldersManager _folders;
public GABUser User { get; private set; }
public UserFolderLoader(StoreTreeNode parent, ZPushAccount account, GABUser user) : base(parent)
public UserFolderLoader(StoreTreeNode parent, SharedFoldersManager folders, GABUser user) : base(parent)
{
this._account = account;
this._folders = folders;
this.User = user;
}
protected override object DoLoadChildren(KTreeNode node)
{
using (SharedFoldersAPI folders = new SharedFoldersAPI(_account))
{
return folders.GetUserFolders(User);
}
return _folders.GetStoreFolders(User);
}
private class FolderComparer : IComparer<AvailableFolder>

View File

@ -199,7 +199,7 @@ namespace Acacia
SyncType.RecipientCache, // RecipientCache = 19
};
public static bool IsMailType(SyncType type)
public static bool IsMail(this SyncType type)
{
return USER_SYNC_TYPES[(int)type] == SyncType.UserMail;
}
@ -245,6 +245,11 @@ namespace Acacia
#endregion
public static bool IsAppointment(this SyncType type)
{
return USER_SYNC_TYPES[(int)type] == SyncType.UserAppointment;
}
#region Message classes
public const string PR_MESSAGE_CLASS = PROP + "001A" + PT_UNICODE;

View File

@ -170,7 +170,7 @@ namespace Acacia
_operands.Add(operand);
}
public ICollection<SearchQuery> Operands
public IList<SearchQuery> Operands
{
get { return _operands; }
}

View File

@ -94,8 +94,6 @@ namespace Acacia.ZPush.API.SharedFolders
public GABUser Store { get; private set; }
public bool IsMailFolder { get { return OutlookConstants.IsMailType(Type); } }
#endregion
#region Tree structure

View File

@ -117,7 +117,7 @@ namespace Acacia.ZPush.API.SharedFolders
parentid = folder.ParentIdAsBackend,
name = folder.DefaultName,
type = OutlookConstants.USER_SYNC_TYPES[(int)folder.Type],
flags = folder.IsMailFolder ? ShareFlags.SendAsOwner : ShareFlags.None
flags = folder.Type.IsMail() ? ShareFlags.SendAsOwner : ShareFlags.None
};
}
@ -129,6 +129,7 @@ namespace Acacia.ZPush.API.SharedFolders
public BackendId BackendId { get { return _data.folderid; } }
public SyncId SyncId { get { return _data.syncfolderid; } }
public bool IsSynced { get { return SyncId != null; } }
public OutlookConstants.SyncType SyncType { get { return _data.type; } }
public Permission? Permissions
{
@ -180,6 +181,7 @@ namespace Acacia.ZPush.API.SharedFolders
public bool FlagSendAsOwner { get { return Flags.HasFlag(ShareFlags.SendAsOwner); } }
public bool FlagUpdateShareName { get { return Flags.HasFlag(ShareFlags.TrackShareName); } }
public bool FlagCalendarReminders { get { return Flags.HasFlag(ShareFlags.CalendarReminders); } }
/// <summary>
/// Returns a copy with the specified 'send as owner' flag.
@ -192,11 +194,19 @@ namespace Acacia.ZPush.API.SharedFolders
/// <summary>
/// Returns a copy with the specified 'update share name' flag.
/// </summary>
public SharedFolder WithFlagUpdateShareName(bool value)
public SharedFolder WithFlagTrackShareName(bool value)
{
return WithFlags(value ? (_data.flags | ShareFlags.TrackShareName) : (_data.flags & ~ShareFlags.TrackShareName));
}
/// <summary>
/// Returns a copy with the specified 'calendar reminders' flag.
/// </summary>
public SharedFolder WithFlagCalendarReminders(bool value)
{
return WithFlags(value ? (_data.flags | ShareFlags.CalendarReminders) : (_data.flags & ~ShareFlags.CalendarReminders));
}
#endregion
#region Standard overrides

View File

@ -40,11 +40,16 @@ namespace Acacia.ZPush.API.SharedFolders
/// </summary>
TrackShareName = 2,
/// <summary>
/// Applicable to calendars only. Set to enable reminders on the shared calendar.
/// </summary>
CalendarReminders = 4,
/// <summary>
/// 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.
/// </summary>
Mask_Apply = 1
Mask_Apply = 0xFFFF & ~(TrackShareName)
}
/// <summary>