118 lines
3.3 KiB
C#
118 lines
3.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using Android.App;
|
|
using Android.Content;
|
|
using KeePassLib.Serialization;
|
|
using keepass2android.Io;
|
|
|
|
namespace keepass2android
|
|
{
|
|
public class SynchronizeCachedDatabase: RunnableOnFinish
|
|
{
|
|
private readonly Context _context;
|
|
private readonly IKp2aApp _app;
|
|
private SaveDb _saveDb;
|
|
|
|
public SynchronizeCachedDatabase(Context context, IKp2aApp app, OnFinish finish)
|
|
: base(finish)
|
|
{
|
|
_context = context;
|
|
_app = app;
|
|
}
|
|
|
|
public override void Run()
|
|
{
|
|
try
|
|
{
|
|
IOConnectionInfo ioc = _app.GetDb().Ioc;
|
|
IFileStorage fileStorage = _app.GetFileStorage(ioc);
|
|
if (!(fileStorage is CachingFileStorage))
|
|
{
|
|
throw new Exception("Cannot sync a non-cached database!");
|
|
}
|
|
StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase);
|
|
CachingFileStorage cachingFileStorage = (CachingFileStorage) fileStorage;
|
|
|
|
//download file from remote location and calculate hash:
|
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile));
|
|
string hash;
|
|
|
|
MemoryStream remoteData;
|
|
try
|
|
{
|
|
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
|
|
}
|
|
catch (FileNotFoundException)
|
|
{
|
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
|
|
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
|
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
|
return;
|
|
}
|
|
|
|
//check if remote file was modified:
|
|
if (cachingFileStorage.GetBaseVersionHash(ioc) != hash)
|
|
{
|
|
//remote file is modified
|
|
if (cachingFileStorage.HasLocalChanges(ioc))
|
|
{
|
|
//conflict! need to merge
|
|
_saveDb = new SaveDb(_context, _app, new ActionOnFinish((success, result) =>
|
|
{
|
|
if (!success)
|
|
{
|
|
Finish(false, result);
|
|
}
|
|
else
|
|
{
|
|
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
|
}
|
|
_saveDb = null;
|
|
}), false, remoteData);
|
|
_saveDb.Run();
|
|
|
|
_app.GetDb().MarkAllGroupsAsDirty();
|
|
}
|
|
else
|
|
{
|
|
//only the remote file was modified -> reload database.
|
|
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
|
|
_app.TriggerReload(_context);
|
|
Finish(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//remote file is unmodified
|
|
if (cachingFileStorage.HasLocalChanges(ioc))
|
|
{
|
|
//but we have local changes -> upload:
|
|
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile));
|
|
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
|
|
StatusLogger.UpdateSubMessage("");
|
|
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
|
|
}
|
|
else
|
|
{
|
|
//files are in sync: just set the result
|
|
Finish(true, _app.GetResourceString(UiStringKey.FilesInSync));
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Finish(false, e.Message);
|
|
}
|
|
|
|
}
|
|
|
|
public void JoinWorkerThread()
|
|
{
|
|
if (_saveDb != null)
|
|
_saveDb.JoinWorkerThread();
|
|
}
|
|
}
|
|
}
|