diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
index 9d3ca76..e889d57 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SyncState/FeatureSyncState.cs
@@ -77,6 +77,29 @@ namespace Acacia.Features.SyncState
}
+ [AcaciaOption("Enables or disables checking for stalled synchronsation. If this is detected, a full resynchronisation " +
+ "is suggested automatically")]
+ public bool CheckSyncStall
+ {
+ get { return GetOption(OPTION_CHECK_SYNC_STALL); }
+ set { SetOption(OPTION_CHECK_SYNC_STALL, value); }
+ }
+ private static readonly BoolOption OPTION_CHECK_SYNC_STALL = new BoolOption("CheckSyncStall", false);
+
+ [AcaciaOption("Sets the period that triggers a full resynchronisation suggestion. Note that the check is only performed " +
+ "when the synchronisation state is being updated, so the effective period may be longer than this.")]
+ public TimeSpan CheckSyncStallPeriod
+ {
+ get { return GetOption(OPTION_CHECK_SYNC_STALL_PERIOD); }
+ set { SetOption(OPTION_CHECK_SYNC_STALL_PERIOD, value); }
+ }
+ private static readonly TimeSpanOption OPTION_CHECK_SYNC_STALL_PERIOD = new TimeSpanOption("CheckSyncStallPeriod", new TimeSpan(0, 10, 0));
+ ///
+ /// The time at which a sync stall was first suspected, or null if this is not the case.
+ ///
+ private DateTime? _syncStallStarted;
+ private bool _syncStallAsked;
+
#endregion
// TODO: this is largely about progress bars, separate that?
@@ -223,9 +246,13 @@ namespace Acacia.Features.SyncState
[SoapField(5)]
public string id;
+ ///
+ /// The key, which is a short folder id. Set when checking the values.
+ ///
public string Key
{
- get { return id; }
+ get;
+ set;
}
}
@@ -320,8 +347,11 @@ namespace Acacia.Features.SyncState
HashSet syncingNow = new HashSet();
// Check all syncing data
- foreach (DeviceDetails.ContentData content in details.Content.Values)
+ foreach (KeyValuePair contentEntry in details.Content)
{
+ DeviceDetails.ContentData content = contentEntry.Value;
+ content.Key = contentEntry.Key;
+
if (content.IsSyncing)
{
// If the current session is not syncing, this is a restart. Clear stat
@@ -370,6 +400,15 @@ namespace Acacia.Features.SyncState
debug.AppendLine(string.Format("Total: {0} / {1} ({2}%)", Done, Total, CalculatePercentage(Done, Total)));
Logger.Instance.Trace(_feature, "Syncing account {0}:\n{1}", _account, debug);
}
+
+ public bool HasFolderSynced(string folderId)
+ {
+ DeviceDetails.ContentData content;
+ if (!_syncContent.TryGetValue(folderId, out content))
+ return false;
+
+ return !string.IsNullOrWhiteSpace(content.synckey);
+ }
}
private void CheckSyncState(ZPushAccount account)
@@ -406,6 +445,9 @@ namespace Acacia.Features.SyncState
// Update the total for all accounts
UpdateTotalSyncState();
+
+ // Check for stalls
+ CheckSyncStalled(account);
}
private void UpdateTotalSyncState()
@@ -442,6 +484,60 @@ namespace Acacia.Features.SyncState
}
}
+ private void CheckSyncStalled(ZPushAccount account)
+ {
+ if (!CheckSyncStall)
+ return;
+
+ // Check the inbox folder
+ using (IFolder inbox = account.Account.Store.GetDefaultFolder(DefaultFolder.Inbox))
+ {
+ string syncId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_SYNC_ID);
+
+ // If it's syncing, it's not stalled
+ if (syncId != null && syncId != "0")
+ return;
+
+ // Check if the folder has synced. In that case, it's not stalled.
+ string folderId = (string)inbox.GetProperty(OutlookConstants.PR_ZPUSH_FOLDER_ID);
+ SyncSession sync = account.GetFeatureData(this, null);
+ if (sync.HasFolderSynced(folderId))
+ return;
+ }
+
+ // It is not syncing, check for a stall
+ if (_syncStallStarted == null)
+ _syncStallStarted = DateTime.Now;
+ else if (_syncStallStarted.Value.Add(CheckSyncStallPeriod) <= DateTime.Now)
+ {
+ // We have a stall
+ if (!_syncStallAsked)
+ {
+ // Set the flag to prevent asking again
+ _syncStallAsked = true;
+
+ // And alert the user
+ SyncStalled(account);
+ }
+ }
+ }
+
+ private void SyncStalled(ZPushAccount account)
+ {
+ ThisAddIn.Instance.InUI(() =>
+ {
+ if (MessageBox.Show(ThisAddIn.Instance.Window,
+ string.Format(Properties.Resources.SyncState_Stalled_Body, account.DisplayName),
+ string.Format(Properties.Resources.SyncState_Stalled_Caption, account.DisplayName),
+ MessageBoxButtons.YesNo,
+ MessageBoxIcon.Error
+ ) == DialogResult.Yes)
+ {
+ ThisAddIn.Instance.RestartResync(account);
+ }
+ });
+ }
+
private static int CalculatePercentage(long done, long total)
{
if (total == 0 || done == total)
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
index b682be8..4e6cc5e 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/OutlookConstants.cs
@@ -132,8 +132,9 @@ namespace Acacia
#region EAS / ZPush
- public const string PR_ZPUSH_MESSAGE_ID = PROP + "6B20" + PT_STRING8;
+ 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_MESSAGE_ID = PROP + "6B20" + PT_STRING8;
// TODO: names for these, use MFCMAPI
public const string PR_EAS_SYNC1 = PROP + "6A17" + PT_BOOLEAN;
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
index e8a4977..dd440d8 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.Designer.cs
@@ -1201,6 +1201,24 @@ namespace Acacia.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to It appears synchronisation has stalled for account {0}. This can be fixed by performing a full resynchronisation. Would you like to perform this resynchronisation now?.
+ ///
+ internal static string SyncState_Stalled_Body {
+ get {
+ return ResourceManager.GetString("SyncState_Stalled_Body", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Synchronisation stalled - {0}.
+ ///
+ internal static string SyncState_Stalled_Caption {
+ get {
+ return ResourceManager.GetString("SyncState_Stalled_Caption", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Kopano.
///
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
index 4d3f06d..b519732 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Properties/Resources.resx
@@ -500,4 +500,12 @@
Global Address Book
+
+ It appears synchronisation has stalled for account {0}. This can be fixed by performing a full resynchronisation. Would you like to perform this resynchronisation now?
+ {0} will be replaced with the account name
+
+
+ Synchronisation stalled - {0}
+ {0} will be replaced with the account name
+
\ No newline at end of file
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs
index 87d7110..473da0c 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Stubs/IAddIn.cs
@@ -71,7 +71,7 @@ namespace Acacia.Stubs
/// Restarts the application and removes the specified account files.
///
///
- void RestartResync(ZPushAccount[] accounts);
+ void RestartResync(params ZPushAccount[] accounts);
void Quit(bool closeWindows);