diff --git a/AES_GCM/AES_GCM.vcxproj b/AES_GCM/AES_GCM.vcxproj
index b97d9115f..57892bcdd 100644
--- a/AES_GCM/AES_GCM.vcxproj
+++ b/AES_GCM/AES_GCM.vcxproj
@@ -34,7 +34,7 @@
14.0
true
Windows Store
- 10.0.17134.0
+ 10.0.17763.0
10.0.15063.0
10.0
diff --git a/BackgroundSocket/BackgroundSocket.csproj b/BackgroundSocket/BackgroundSocket.csproj
index 7462499f0..b57c26710 100644
--- a/BackgroundSocket/BackgroundSocket.csproj
+++ b/BackgroundSocket/BackgroundSocket.csproj
@@ -4,15 +4,15 @@
Debug
AnyCPU
- {2343CA08-3D0A-4412-A0ED-E8E68E0E208B}
+ {94944B01-6CE9-42BB-9180-7682BCE2298F}
winmdobj
Properties
BackgroundSocket
BackgroundSocket
- de-DE
+ en-US
UAP
- 10.0.16299.0
- 10.0.10586.0
+ 10.0.17763.0
+ 10.0.15063.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -27,6 +27,7 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
AnyCPU
@@ -36,6 +37,7 @@
TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
x86
@@ -44,9 +46,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x86
false
prompt
+ latest
x86
@@ -55,9 +57,9 @@
true
;2008
pdbonly
- x86
false
prompt
+ latest
ARM
@@ -66,9 +68,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- ARM
false
prompt
+ latest
ARM
@@ -77,9 +79,31 @@
true
;2008
pdbonly
- ARM
false
prompt
+ latest
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+ latest
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+ latest
x64
@@ -88,9 +112,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x64
false
prompt
+ latest
x64
@@ -99,36 +123,35 @@
true
;2008
pdbonly
- x64
false
prompt
+ latest
PackageReference
-
- 6.2.2
+ 6.2.3
-
-
-
- {53bb5463-9646-4f79-be97-3d73473aad92}
+ {0c1fb090-4492-441d-b182-c999df71f917}
Logging
- {899fb043-af8b-4294-95b6-1482c79459ac}
+ {64b9a47f-d404-4d0b-a34a-bec280c5ff6b}
XMPP_API
+
+
+
14.0
diff --git a/BackgroundSocket/Properties/AssemblyInfo.cs b/BackgroundSocket/Properties/AssemblyInfo.cs
index b1666fbeb..2567ae0d6 100644
--- a/BackgroundSocket/Properties/AssemblyInfo.cs
+++ b/BackgroundSocket/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BackgroundSocket")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/Component_Tests/Classes/Crypto/Test_CryptoUtils.cs b/Component_Tests/Classes/Crypto/Test_CryptoUtils.cs
index d6836dbc4..c6a6265e8 100644
--- a/Component_Tests/Classes/Crypto/Test_CryptoUtils.cs
+++ b/Component_Tests/Classes/Crypto/Test_CryptoUtils.cs
@@ -1,4 +1,5 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using libsignal;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Text;
@@ -123,5 +124,19 @@ public void Test_CryptoUtils_HexToByteArray()
string saltStringHex = CryptoUtils.byteArrayToHexString(salt);
Assert.IsTrue(saltStringHex.Equals(saltStringHexRef));
}
+
+ [TestCategory("Crypto")]
+ [TestMethod]
+ public void Test_CryptoUtils_GenOmemoFingerprint()
+ {
+ string identKeyPairSerializedHex = "0a210511dbad7fcece74492f390f0a2a8387c543e802ab7f2176e303e28840559c41521220a082ae07fd8941536457cb2f3e4b560a87991d380f02af460b5204e46ca7b15a";
+ byte[] identKeyPairSerialized = CryptoUtils.hexStringToByteArray(identKeyPairSerializedHex);
+ IdentityKeyPair identKeyPair = new IdentityKeyPair(identKeyPairSerialized);
+
+ string outputRef = "11dbad7f cece7449 2f390f0a 2a8387c5 43e802ab 7f2176e3 03e28840 559c4152";
+ string output = CryptoUtils.generateOmemoFingerprint(identKeyPair.getPublicKey(), false);
+
+ Assert.AreEqual(outputRef, output);
+ }
}
}
diff --git a/Component_Tests/Classes/Misc/Test_JidParser.cs b/Component_Tests/Classes/Misc/Test_JidParser.cs
new file mode 100644
index 000000000..2d8d2aaa0
--- /dev/null
+++ b/Component_Tests/Classes/Misc/Test_JidParser.cs
@@ -0,0 +1,156 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using XMPP_API.Classes;
+
+namespace Component_Tests.Classes.Misc
+{
+ ///
+ /// Examples from: https://tools.ietf.org/html/rfc7622#section-3.5
+ ///
+ [TestClass]
+ public class Test_JidParser
+ {
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_1()
+ {
+ string s = "juliet@example.com";
+ Assert.IsTrue(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_2()
+ {
+ string s = "foo\\20bar@example.com";
+ Assert.IsTrue(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_3()
+ {
+ string s = "fussball@example.com";
+ Assert.IsTrue(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_4()
+ {
+ string s = "fußball@example.com";
+ //Assert.IsTrue(Utils.isBareJid(s)); // TODO: Fix RFC 7622 encoding
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_5()
+ {
+ string s = "π@example.com";
+ //Assert.IsTrue(Utils.isBareJid(s)); // TODO: Fix RFC 7622 encoding
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_6()
+ {
+ string s = "\"juliet\"@example.com";
+ Assert.IsFalse(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_7()
+ {
+ string s = "foo bar@example.com";
+ Assert.IsFalse(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsBareJid_8()
+ {
+ string s = "juliet@";
+ Assert.IsFalse(Utils.isBareJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_1()
+ {
+ string s = "juliet@example.com/foo";
+ Assert.IsTrue(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_2()
+ {
+ string s = "juliet@example.com/foo bar";
+ Assert.IsTrue(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_3()
+ {
+ string s = "juliet@example.com/foo@bar";
+ Assert.IsTrue(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_4()
+ {
+ string s = "Σ@example.com/foo";
+ //Assert.IsTrue(Utils.isFullJid(s)); // TODO: Fix RFC 7622 encoding
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_5()
+ {
+ string s = "σ@example.com/foo";
+ //Assert.IsTrue(Utils.isFullJid(s)); // TODO: Fix RFC 7622 encoding
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_6()
+ {
+ string s = "ς@example.com/foo";
+ //Assert.IsTrue(Utils.isFullJid(s)); // TODO: Fix RFC 7622 encoding
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_7()
+ {
+ string s = "king@example.com/♚";
+ Assert.IsTrue(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_8()
+ {
+ string s = "a@a.example.com/b@example.net";
+ Assert.IsTrue(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_9()
+ {
+ string s = "juliet@example.com/ foo";
+ Assert.IsFalse(Utils.isFullJid(s));
+ }
+
+ [TestCategory("Misc")]
+ [TestMethod]
+ public void Test_IsFullJid_10()
+ {
+ string s = "@example.com/";
+ Assert.IsFalse(Utils.isFullJid(s));
+ }
+ }
+}
diff --git a/Component_Tests/Component_Tests.csproj b/Component_Tests/Component_Tests.csproj
index 5b4ceb406..ec80e0220 100644
--- a/Component_Tests/Component_Tests.csproj
+++ b/Component_Tests/Component_Tests.csproj
@@ -4,15 +4,15 @@
Debug
x86
- {0C3E37F5-FF21-41B5-8C9F-492A5536471C}
+ {B7A8F92E-7BD9-46F5-BFC6-4EBCD8AD062F}
AppContainerExe
Properties
Component_Tests
Component_Tests
en-US
UAP
- 10.0.17134.0
- 10.0.14393.0
+ 10.0.17763.0
+ 10.0.15063.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -29,6 +29,7 @@
false
prompt
true
+ latest
bin\x86\Release\
@@ -41,6 +42,7 @@
prompt
true
true
+ latest
true
@@ -52,6 +54,7 @@
false
prompt
true
+ latest
bin\ARM\Release\
@@ -64,6 +67,33 @@
prompt
true
true
+ latest
+
+
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM64
+ false
+ prompt
+ true
+ true
+ latest
+
+
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM64
+ false
+ prompt
+ true
+ true
+ latest
true
@@ -75,6 +105,7 @@
false
prompt
true
+ latest
bin\x64\Release\
@@ -87,12 +118,12 @@
prompt
true
true
+ latest
PackageReference
-
@@ -100,11 +131,12 @@
+
-
+
@@ -125,6 +157,7 @@
+
@@ -132,11 +165,10 @@
-
- 6.2.2
+ 6.2.3
1.4.0
@@ -145,20 +177,23 @@
1.4.0
- 15.9.0
+ 16.0.1
- {53BB5463-9646-4F79-BE97-3D73473AAD92}
+ {0c1fb090-4492-441d-b182-c999df71f917}
Logging
+
+ {c4af94da-11cf-4147-b5b7-4b2dc7c624a0}
+ Shared
+
- {899FB043-AF8B-4294-95B6-1482C79459AC}
+ {64b9a47f-d404-4d0b-a34a-bec280c5ff6b}
XMPP_API
-
14.0
diff --git a/Component_Tests/Component_Tests_TemporaryKey.pfx b/Component_Tests/Component_Tests_TemporaryKey.pfx
index 128e93985..71431443e 100644
Binary files a/Component_Tests/Component_Tests_TemporaryKey.pfx and b/Component_Tests/Component_Tests_TemporaryKey.pfx differ
diff --git a/Component_Tests/Package.appxmanifest b/Component_Tests/Package.appxmanifest
index a52c96e7b..22f6b8685 100644
--- a/Component_Tests/Package.appxmanifest
+++ b/Component_Tests/Package.appxmanifest
@@ -1,23 +1,40 @@
-
-
-
+
+
+
+
+
+
Component_Tests
saute
Assets\StoreLogo.png
+
+
-
-
-
-
+
+
+
diff --git a/Component_Tests/Properties/AssemblyInfo.cs b/Component_Tests/Properties/AssemblyInfo.cs
index de6076aeb..179b9f922 100644
--- a/Component_Tests/Properties/AssemblyInfo.cs
+++ b/Component_Tests/Properties/AssemblyInfo.cs
@@ -7,7 +7,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Component_Tests")]
-[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyMetadata("TargetPlatform","UAP")]
diff --git a/Component_Tests/Properties/UnitTestApp.rd.xml b/Component_Tests/Properties/UnitTestApp.rd.xml
index efee59d27..996a8392a 100644
--- a/Component_Tests/Properties/UnitTestApp.rd.xml
+++ b/Component_Tests/Properties/UnitTestApp.rd.xml
@@ -3,7 +3,7 @@
developers. However, you can modify these parameters to modify the behavior of the .NET Native
optimizer.
- Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
+ Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
To fully enable reflection for App1.MyClass and all of its public/private members
@@ -12,7 +12,7 @@
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
-
+
-->
diff --git a/Component_Tests/UnitTestApp.xaml b/Component_Tests/UnitTestApp.xaml
index fe9f98d17..a8bae5e17 100644
--- a/Component_Tests/UnitTestApp.xaml
+++ b/Component_Tests/UnitTestApp.xaml
@@ -1,6 +1,7 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="using:Component_Tests">
diff --git a/Component_Tests/UnitTestApp.xaml.cs b/Component_Tests/UnitTestApp.xaml.cs
index 2e4504250..4cb5667e8 100644
--- a/Component_Tests/UnitTestApp.xaml.cs
+++ b/Component_Tests/UnitTestApp.xaml.cs
@@ -1,11 +1,18 @@
-using Logging;
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace Component_Tests
@@ -32,6 +39,7 @@ public App()
/// Details about the launch request and process.
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
+
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
@@ -43,7 +51,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
- if (rootFrame is null)
+ if (rootFrame == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
rootFrame = new Frame();
diff --git a/Data_Manager2/Classes/ConnectionHandler.cs b/Data_Manager2/Classes/ConnectionHandler.cs
index 2ae278268..b96c9e7e7 100644
--- a/Data_Manager2/Classes/ConnectionHandler.cs
+++ b/Data_Manager2/Classes/ConnectionHandler.cs
@@ -1,23 +1,27 @@
-using Data_Manager2.Classes.Events;
-using Data_Manager2.Classes.DBManager;
+using Data_Manager2.Classes.DBManager;
using Data_Manager2.Classes.DBTables;
+using Data_Manager2.Classes.Events;
+using Data_Manager2.Classes.Omemo;
+using Data_Manager2.Classes.Toast;
using Logging;
+using Shared.Classes.Collections;
+using Shared.Classes.Network;
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Threading;
using System.Threading.Tasks;
using XMPP_API.Classes;
using XMPP_API.Classes.Network;
+using XMPP_API.Classes.Network.Events;
using XMPP_API.Classes.Network.XML;
using XMPP_API.Classes.Network.XML.Messages;
using XMPP_API.Classes.Network.XML.Messages.XEP_0045;
-using XMPP_API.Classes.Network.XML.Messages.XEP_0249;
-using System.Threading;
using XMPP_API.Classes.Network.XML.Messages.XEP_0048;
using XMPP_API.Classes.Network.XML.Messages.XEP_0184;
-using XMPP_API.Classes.Network.Events;
+using XMPP_API.Classes.Network.XML.Messages.XEP_0249;
using XMPP_API.Classes.Network.XML.Messages.XEP_0384;
-using Data_Manager2.Classes.Toast;
-using Data_Manager2.Classes.Omemo;
+using XMPP_API.Classes.Network.XML.Messages.XEP_0384.Signal.Session;
namespace Data_Manager2.Classes
{
@@ -27,11 +31,15 @@ public class ConnectionHandler
#region --Attributes--
private static readonly SemaphoreSlim CLIENT_SEMA = new SemaphoreSlim(1);
public static readonly ConnectionHandler INSTANCE = new ConnectionHandler();
- private readonly List CLIENTS;
+ private readonly CustomObservableCollection CLIENTS;
+ private readonly DownloadHandler DOWNLOAD_HANDLER = new DownloadHandler();
+ public readonly ImageDownloadHandler IMAGE_DOWNLOAD_HANDLER;
public delegate void ClientConnectedHandler(ConnectionHandler handler, ClientConnectedEventArgs args);
+ public delegate void ClientsCollectionChangedHandler(ConnectionHandler handler, NotifyCollectionChangedEventArgs args);
public event ClientConnectedHandler ClientConnected;
+ public event ClientsCollectionChangedHandler ClientsCollectionChanged;
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
@@ -43,7 +51,10 @@ public class ConnectionHandler
///
public ConnectionHandler()
{
- this.CLIENTS = new List();
+ this.IMAGE_DOWNLOAD_HANDLER = new ImageDownloadHandler(DOWNLOAD_HANDLER);
+ Task.Run(async () => await this.IMAGE_DOWNLOAD_HANDLER.ContinueDownloadsAsync());
+ this.CLIENTS = new CustomObservableCollection(false);
+ this.CLIENTS.CollectionChanged += CLIENTS_CollectionChanged;
loadClients();
AccountDBManager.INSTANCE.AccountChanged += INSTANCE_AccountChanged;
}
@@ -59,7 +70,7 @@ public XMPPClient getClient(string iDAndDomain)
{
foreach (XMPPClient c in CLIENTS)
{
- if (c.getXMPPAccount().getIdAndDomain().Equals(iDAndDomain))
+ if (c.getXMPPAccount().getBareJid().Equals(iDAndDomain))
{
return c;
}
@@ -70,7 +81,7 @@ public XMPPClient getClient(string iDAndDomain)
///
/// Returns all available XMPPClients.
///
- public List getClients()
+ public CustomObservableCollection getClients()
{
return CLIENTS;
}
@@ -144,7 +155,7 @@ public async Task removeAccountAsync(string accountId)
CLIENT_SEMA.Wait();
for (int i = 0; i < CLIENTS.Count; i++)
{
- if (Equals(CLIENTS[i].getXMPPAccount().getIdAndDomain(), accountId))
+ if (Equals(CLIENTS[i].getXMPPAccount().getBareJid(), accountId))
{
await CLIENTS[i].disconnectAsync();
CLIENTS.RemoveAt(i);
@@ -246,7 +257,7 @@ private void unsubscribeFromEvents(XMPPClient c)
/// The Client which entered the state.
private void onClientDisconnectedOrError(XMPPClient client)
{
- ChatDBManager.INSTANCE.resetPresence(client.getXMPPAccount().getIdAndDomain());
+ ChatDBManager.INSTANCE.resetPresence(client.getXMPPAccount().getBareJid());
MUCHandler.INSTANCE.onClientDisconnected(client);
}
@@ -309,7 +320,7 @@ private void setOmemoChatMessagesSendFailed(IList messages,
#endregion
//--------------------------------------------------------Events:---------------------------------------------------------------------\\
#region --Events--
- private void C_ConnectionStateChanged(XMPPClient client, XMPP_API.Classes.Network.Events.ConnectionStateChangedEventArgs args)
+ private void C_ConnectionStateChanged(XMPPClient client, ConnectionStateChangedEventArgs args)
{
switch (args.newState)
{
@@ -337,7 +348,7 @@ private async Task answerPresenceProbeAsync(string from, string to, ChatTable ch
PresenceMessage answer = null;
if (chat is null)
{
- answer = new PresenceErrorMessage(account.getIdDomainAndResource(), from, PresenceErrorType.FORBIDDEN);
+ answer = new PresenceErrorMessage(account.getFullJid(), from, PresenceErrorType.FORBIDDEN);
Logger.Warn("Received a presence probe message for an unknown chat from: " + from + ", to: " + to);
return;
}
@@ -347,18 +358,18 @@ private async Task answerPresenceProbeAsync(string from, string to, ChatTable ch
{
case "both":
case "from":
- answer = new PresenceMessage(account.getIdAndDomain(), from, account.presence, account.status, account.presencePriorety);
+ answer = new PresenceMessage(account.getBareJid(), from, account.presence, account.status, account.presencePriorety);
Logger.Debug("Answered presence probe from: " + from);
break;
case "none" when chat.inRoster:
case "to" when chat.inRoster:
- answer = new PresenceErrorMessage(account.getIdDomainAndResource(), from, PresenceErrorType.FORBIDDEN);
+ answer = new PresenceErrorMessage(account.getFullJid(), from, PresenceErrorType.FORBIDDEN);
Logger.Warn("Received a presence probe but chat has no subscription: " + from + ", to: " + to + " subscription: " + chat.subscription);
break;
default:
- answer = new PresenceErrorMessage(account.getIdDomainAndResource(), from, PresenceErrorType.NOT_AUTHORIZED);
+ answer = new PresenceErrorMessage(account.getFullJid(), from, PresenceErrorType.NOT_AUTHORIZED);
Logger.Warn("Received a presence probe but chat has no subscription: " + from + ", to: " + to + " subscription: " + chat.subscription);
break;
}
@@ -371,12 +382,12 @@ private async void C_NewPresence(XMPPClient client, XMPP_API.Classes.Events.NewP
string from = Utils.getBareJidFromFullJid(args.PRESENCE_MESSAGE.getFrom());
// If received a presence message from your own account, ignore it:
- if (string.Equals(from, client.getXMPPAccount().getIdAndDomain()))
+ if (string.Equals(from, client.getXMPPAccount().getBareJid()))
{
return;
}
- string to = client.getXMPPAccount().getIdAndDomain();
+ string to = client.getXMPPAccount().getBareJid();
string id = ChatTable.generateId(from, to);
ChatTable chat = ChatDBManager.INSTANCE.getChat(id);
switch (args.PRESENCE_MESSAGE.TYPE)
@@ -415,12 +426,12 @@ private void C_NewRoosterMessage(IMessageSender sender, NewValidMessageEventArgs
{
if (args.MESSAGE is RosterResultMessage msg && sender is XMPPClient client)
{
- string to = client.getXMPPAccount().getIdAndDomain();
+ string to = client.getXMPPAccount().getBareJid();
string type = msg.TYPE;
if (string.Equals(type, IQMessage.RESULT))
{
- ChatDBManager.INSTANCE.setAllNotInRoster(client.getXMPPAccount().getIdAndDomain());
+ ChatDBManager.INSTANCE.setAllNotInRoster(client.getXMPPAccount().getBareJid());
}
else if (!string.Equals(type, IQMessage.SET))
{
@@ -488,17 +499,6 @@ private void C_NewChatMessage(XMPPClient client, XMPP_API.Classes.Network.Events
}
string from = Utils.getBareJidFromFullJid(msg.getFrom());
-
- // Check if device id is valid and if, decrypt the OMEMO messages:
- if (msg is OmemoMessageMessage omemoMessage)
- {
- // Decryption failed:
- if (!omemoMessage.decrypt(client.getOmemoHelper(), client.getXMPPAccount().omemoDeviceId))
- {
- return;
- }
- }
-
string to = Utils.getBareJidFromFullJid(msg.getTo());
string id;
if (msg.CC_TYPE == CarbonCopyType.SENT)
@@ -510,9 +510,44 @@ private void C_NewChatMessage(XMPPClient client, XMPP_API.Classes.Network.Events
id = ChatTable.generateId(from, to);
}
+ // Check if device id is valid and if, decrypt the OMEMO messages:
+ if (msg is OmemoMessageMessage omemoMessage)
+ {
+ OmemoHelper helper = client.getOmemoHelper();
+ if (helper is null)
+ {
+ C_OmemoSessionBuildError(client, new XMPP_API.Classes.Events.OmemoSessionBuildErrorEventArgs(id, OmemoSessionBuildError.KEY_ERROR, new List { omemoMessage }));
+ Logger.Error("Failed to decrypt OMEMO message - OmemoHelper is null");
+ return;
+ }
+ else if (!client.getXMPPAccount().checkOmemoKeys())
+ {
+ C_OmemoSessionBuildError(client, new XMPP_API.Classes.Events.OmemoSessionBuildErrorEventArgs(id, OmemoSessionBuildError.KEY_ERROR, new List { omemoMessage }));
+ Logger.Error("Failed to decrypt OMEMO message - keys are corrupted");
+ return;
+ }
+ else if (!omemoMessage.decrypt(client.getOmemoHelper(), client.getXMPPAccount().omemoDeviceId))
+ {
+ return;
+ }
+ }
ChatTable chat = ChatDBManager.INSTANCE.getChat(id);
bool chatChanged = false;
+
+ // Spam detection:
+ if (Settings.getSettingBoolean(SettingsConsts.SPAM_DETECTION_ENABLED))
+ {
+ if (Settings.getSettingBoolean(SettingsConsts.SPAM_DETECTION_FOR_ALL_CHAT_MESSAGES) || chat is null)
+ {
+ if (SpamDBManager.INSTANCE.isSpam(msg.MESSAGE))
+ {
+ Logger.Warn("Received spam message from " + from);
+ return;
+ }
+ }
+ }
+
if (chat is null)
{
chatChanged = true;
@@ -589,7 +624,7 @@ private void C_NewChatMessage(XMPPClient client, XMPP_API.Classes.Network.Events
{
Task.Run(async () =>
{
- DeliveryReceiptMessage receiptMessage = new DeliveryReceiptMessage(client.getXMPPAccount().getIdDomainAndResource(), from, msg.ID);
+ DeliveryReceiptMessage receiptMessage = new DeliveryReceiptMessage(client.getXMPPAccount().getFullJid(), from, msg.ID);
await client.sendAsync(receiptMessage, true);
});
}
@@ -641,7 +676,7 @@ private async void INSTANCE_AccountChanged(AccountDBManager handler, AccountChan
CLIENT_SEMA.Wait();
for (int i = 0; i < CLIENTS.Count; i++)
{
- if (Equals(CLIENTS[i].getXMPPAccount().getIdAndDomain(), args.ACCOUNT.getIdAndDomain()))
+ if (Equals(CLIENTS[i].getXMPPAccount().getBareJid(), args.ACCOUNT.getBareJid()))
{
// Disconnect first:
await CLIENTS[i].disconnectAsync();
@@ -687,7 +722,7 @@ private void C_NewBookmarksResultMessage(XMPPClient client, NewBookmarksResultMe
foreach (ConferenceItem c in args.BOOKMARKS_MESSAGE.STORAGE.CONFERENCES)
{
bool newMUC = false;
- string to = client.getXMPPAccount().getIdAndDomain();
+ string to = client.getXMPPAccount().getBareJid();
string from = c.jid;
string id = ChatTable.generateId(from, to);
@@ -756,7 +791,7 @@ private void C_OmemoSessionBuildError(XMPPClient client, XMPP_API.Classes.Events
{
Task.Run(() =>
{
- ChatTable chat = ChatDBManager.INSTANCE.getChat(ChatTable.generateId(args.CHAT_JID, client.getXMPPAccount().getIdAndDomain()));
+ ChatTable chat = ChatDBManager.INSTANCE.getChat(ChatTable.generateId(args.CHAT_JID, client.getXMPPAccount().getBareJid()));
if (!(chat is null))
{
// Add an error chat message:
@@ -778,6 +813,11 @@ private void C_OmemoSessionBuildError(XMPPClient client, XMPP_API.Classes.Events
}
});
}
+
+ private void CLIENTS_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ ClientsCollectionChanged?.Invoke(this, e);
+ }
#endregion
}
}
diff --git a/Data_Manager2/Classes/DBManager/AccountDBManager.cs b/Data_Manager2/Classes/DBManager/AccountDBManager.cs
index 737c0c3bd..37ab6f3f1 100644
--- a/Data_Manager2/Classes/DBManager/AccountDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/AccountDBManager.cs
@@ -1,12 +1,12 @@
-using Data_Manager2.Classes.Events;
+using Data_Manager2.Classes.DBManager.Omemo;
using Data_Manager2.Classes.DBTables;
-using System.Collections.Generic;
-using XMPP_API.Classes.Network;
-using Windows.Security.Cryptography.Certificates;
+using Data_Manager2.Classes.Events;
using Logging;
+using Shared.Classes.SQLite;
+using System.Collections.Generic;
using System.Threading;
-using Thread_Save_Components.Classes.SQLite;
-using Data_Manager2.Classes.DBManager.Omemo;
+using Windows.Security.Cryptography.Certificates;
+using XMPP_API.Classes.Network;
namespace Data_Manager2.Classes.DBManager
{
@@ -44,26 +44,26 @@ public AccountDBManager()
/// The account which should get inserted or replaced.
public void setAccount(XMPPAccount account, bool triggerAccountChanged)
{
- update(new AccountTable(account));
+ dB.InsertOrReplace(new AccountTable(account));
Vault.storePassword(account);
saveAccountConnectionConfiguration(account);
- if (account.omemoPreKeys != null)
+ if (account.OMEMO_PRE_KEYS != null)
{
- OmemoSignalKeyDBManager.INSTANCE.setPreKeys(account.omemoPreKeys, account.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setPreKeys(account.OMEMO_PRE_KEYS, account.getBareJid());
}
else
{
- OmemoSignalKeyDBManager.INSTANCE.deletePreKeys(account.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deletePreKeys(account.getBareJid());
}
if (account.omemoSignedPreKeyPair != null)
{
- OmemoSignalKeyDBManager.INSTANCE.setSignedPreKey(account.omemoSignedPreKeyId, account.omemoSignedPreKeyPair, account.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setSignedPreKey(account.omemoSignedPreKeyId, account.omemoSignedPreKeyPair, account.getBareJid());
}
else
{
- OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(account.omemoSignedPreKeyId, account.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(account.omemoSignedPreKeyId, account.getBareJid());
}
if (triggerAccountChanged)
@@ -78,7 +78,7 @@ public void setAccount(XMPPAccount account, bool triggerAccountChanged)
/// The XMPPAccount with updated disabled property.
public void setAccountDisabled(XMPPAccount account)
{
- dB.Execute("UPDATE " + DBTableConsts.ACCOUNT_TABLE + " SET disabled = ? WHERE id = ?;", account.disabled, account.getIdAndDomain());
+ dB.Execute("UPDATE " + DBTableConsts.ACCOUNT_TABLE + " SET disabled = ? WHERE id = ?;", account.disabled, account.getBareJid());
AccountChanged?.Invoke(this, new AccountChangedEventArgs(account, false));
}
@@ -134,18 +134,18 @@ public int getAccountCount()
/// Whether to delete all OMEMO keys.
public void deleteAccount(XMPPAccount account, bool triggerAccountChanged, bool deleteAllKeys)
{
- dB.Execute("DELETE FROM " + DBTableConsts.ACCOUNT_TABLE + " WHERE id = ?;", account.getIdAndDomain());
- dB.Execute("DELETE FROM " + DBTableConsts.IGNORED_CERTIFICATE_ERROR_TABLE + " WHERE accountId = ?;", account.getIdAndDomain());
- dB.Execute("DELETE FROM " + DBTableConsts.CONNECTION_OPTIONS_TABLE + " WHERE accountId = ?;", account.getIdAndDomain());
+ dB.Execute("DELETE FROM " + DBTableConsts.ACCOUNT_TABLE + " WHERE id = ?;", account.getBareJid());
+ dB.Execute("DELETE FROM " + DBTableConsts.IGNORED_CERTIFICATE_ERROR_TABLE + " WHERE accountId = ?;", account.getBareJid());
+ dB.Execute("DELETE FROM " + DBTableConsts.CONNECTION_OPTIONS_TABLE + " WHERE accountId = ?;", account.getBareJid());
if (deleteAllKeys)
{
- OmemoDeviceDBManager.INSTANCE.deleteAllForAccount(account.getIdAndDomain());
- OmemoSignalKeyDBManager.INSTANCE.deleteAllForAccount(account.getIdAndDomain());
+ OmemoDeviceDBManager.INSTANCE.deleteAllForAccount(account.getBareJid());
+ OmemoSignalKeyDBManager.INSTANCE.deleteAllForAccount(account.getBareJid());
}
else
{
- OmemoSignalKeyDBManager.INSTANCE.deletePreKeys(account.getIdAndDomain());
- OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(account.omemoSignedPreKeyId, account.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deletePreKeys(account.getBareJid());
+ OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(account.omemoSignedPreKeyId, account.getBareJid());
}
Vault.deletePassword(account);
@@ -208,14 +208,14 @@ public void replaceAccount(XMPPAccount oldAccount, XMPPAccount account)
public void loadAccountConnectionConfiguration(XMPPAccount account)
{
// Load general options:
- ConnectionOptionsTable optionsTable = getConnectionOptionsTable(account.getIdAndDomain());
+ ConnectionOptionsTable optionsTable = getConnectionOptionsTable(account.getBareJid());
if (optionsTable != null)
{
optionsTable.toConnectionConfiguration(account.connectionConfiguration);
}
// Load ignored certificate errors:
- IList ignoredCertificates = getIgnoredCertificateErrorTables(account.getIdAndDomain());
+ IList ignoredCertificates = getIgnoredCertificateErrorTables(account.getBareJid());
if (ignoredCertificates != null)
{
foreach (IgnoredCertificateErrorTable i in ignoredCertificates)
@@ -234,19 +234,19 @@ public void saveAccountConnectionConfiguration(XMPPAccount account)
// Save general options:
ConnectionOptionsTable optionsTable = new ConnectionOptionsTable(account.connectionConfiguration)
{
- accountId = account.getIdAndDomain()
+ accountId = account.getBareJid()
};
- update(optionsTable);
+ dB.InsertOrReplace(optionsTable);
// Save ignored certificate errors:
- dB.Execute("DELETE FROM " + DBTableConsts.IGNORED_CERTIFICATE_ERROR_TABLE + " WHERE accountId = ?;", account.getIdAndDomain());
+ dB.Execute("DELETE FROM " + DBTableConsts.IGNORED_CERTIFICATE_ERROR_TABLE + " WHERE accountId = ?;", account.getBareJid());
foreach (ChainValidationResult i in account.connectionConfiguration.IGNORED_CERTIFICATE_ERRORS)
{
- update(new IgnoredCertificateErrorTable()
+ dB.InsertOrReplace(new IgnoredCertificateErrorTable()
{
- accountId = account.getIdAndDomain(),
+ accountId = account.getBareJid(),
certificateError = i,
- id = IgnoredCertificateErrorTable.generateId(account.getIdAndDomain(), i)
+ id = IgnoredCertificateErrorTable.generateId(account.getBareJid(), i)
});
}
}
diff --git a/Data_Manager2/Classes/DBManager/ChatDBManager.cs b/Data_Manager2/Classes/DBManager/ChatDBManager.cs
index 2793cca59..d81835daf 100644
--- a/Data_Manager2/Classes/DBManager/ChatDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/ChatDBManager.cs
@@ -1,10 +1,11 @@
-using Data_Manager2.Classes.Events;
-using Data_Manager2.Classes.DBTables;
+using Data_Manager2.Classes.DBTables;
+using Data_Manager2.Classes.Events;
+using Shared.Classes.SQLite;
using SQLite;
using System.Collections.Generic;
using System.Threading.Tasks;
using XMPP_API.Classes;
-using Thread_Save_Components.Classes.SQLite;
+using XMPP_API.Classes.Network.XML.Messages.XEP_0249;
namespace Data_Manager2.Classes.DBManager
{
@@ -47,7 +48,7 @@ public void setMessageAsDeliverd(string id, bool triggerMessageChanged)
ChatMessageTable msg = getChatMessageById(id);
if (msg != null)
{
- ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg));
+ ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg, false));
}
}
}
@@ -82,7 +83,7 @@ public ChatTable getChat(string chatId)
public void setMUCDirectInvitation(MUCDirectInvitationTable invite)
{
- update(invite);
+ dB.InsertOrReplace(invite);
}
public void setMUCDirectInvitationState(string chatMessageId, MUCDirectInvitationState state)
@@ -130,7 +131,7 @@ public void setChat(ChatTable chat, bool delete, bool triggerChatChanged)
}
else
{
- update(chat);
+ dB.InsertOrReplace(chat);
}
if (triggerChatChanged)
@@ -154,7 +155,7 @@ public void setAllNotInRoster(string userAccountId)
Parallel.ForEach(getAllChatsForClient(userAccountId), (c) =>
{
c.inRoster = false;
- update(c);
+ dB.InsertOrReplace(c);
onChatChanged(c, false);
});
}
@@ -196,13 +197,26 @@ public void updateChatMessageState(string msgId, MessageState state)
List list = dB.Query(true, "SELECT * FROM " + DBTableConsts.CHAT_MESSAGE_TABLE + " WHERE id = ?;", msgId);
Parallel.ForEach(list, (msg) =>
{
- ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg));
+ ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg, false));
});
}
- public void deleteAllChatMessagesForChat(string chatId)
+ public async Task deleteAllChatMessagesForChatAsync(string chatId)
{
- dB.Execute("DELETE FROM " + DBTableConsts.CHAT_MESSAGE_TABLE + " WHERE chatId = ?;", chatId);
+ List list = dB.Query(true, "SELECT * FROM " + DBTableConsts.CHAT_MESSAGE_TABLE + " WHERE chatId = ?;", chatId);
+ foreach (ChatMessageTable msg in list)
+ {
+ await deleteChatMessageAsync(msg, false);
+ }
+ }
+
+ public async Task deleteAllChatMessagesForAccountAsync(string userAccountId)
+ {
+ List list = dB.Query(true, "SELECT m.* FROM " + DBTableConsts.CHAT_MESSAGE_TABLE + " m JOIN " + DBTableConsts.CHAT_TABLE + " c ON m.chatId = c.id WHERE c.userAccountId = ?;", userAccountId);
+ foreach (ChatMessageTable msg in list)
+ {
+ await deleteChatMessageAsync(msg, false);
+ }
}
public void deleteAllChatsForAccount(string userAccountId)
@@ -231,28 +245,52 @@ public void markMessageAsRead(string id)
public void markMessageAsRead(ChatMessageTable msg)
{
msg.state = MessageState.READ;
- update(msg);
+ dB.InsertOrReplace(msg);
msg.onChanged();
- ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg));
+ ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(msg, false));
}
public void setChatMessage(ChatMessageTable message, bool triggerNewChatMessage, bool triggerMessageChanged)
{
- update(message);
+ dB.InsertOrReplace(message);
if (triggerNewChatMessage)
{
NewChatMessage?.Invoke(this, new NewChatMessageEventArgs(message));
- if (message.isImage)
+ if (message.isImage && !Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
{
cacheImage(message);
}
}
if (triggerMessageChanged)
{
- ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message));
+ ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message, false));
+ }
+ }
+
+ public async Task deleteChatMessageAsync(ChatMessageTable message, bool triggerMessageChanged)
+ {
+ if (message.isImage)
+ {
+ await ImageDBManager.INSTANCE.deleteImageAsync(message);
+ }
+
+ if (string.Equals(message.type, DirectMUCInvitationMessage.TYPE_MUC_DIRECT_INVITATION))
+ {
+ deleteMucDirectInvite(message);
+ }
+
+ dB.Delete(message);
+ if (triggerMessageChanged)
+ {
+ ChatMessageChanged?.Invoke(this, new ChatMessageChangedEventArgs(message, true));
}
}
+ public void deleteMucDirectInvite(ChatMessageTable message)
+ {
+ dB.Execute("DELETE FROM " + DBTableConsts.MUC_DIRECT_INVITATION_TABLE + " WHERE chatMessageId = ?;", message.id);
+ }
+
public void resetPresence(string userAccountId)
{
foreach (ChatTable c in getAllChatsForClient(userAccountId))
@@ -260,7 +298,7 @@ public void resetPresence(string userAccountId)
if (c.chatType == ChatType.CHAT)
{
c.presence = Presence.Unavailable;
- update(c);
+ dB.InsertOrReplace(c);
onChatChanged(c, false);
}
}
@@ -284,7 +322,10 @@ private void onChatChanged(string chatId)
private void cacheImage(ChatMessageTable msg)
{
- ImageDBManager.INSTANCE.downloadImage(msg);
+ if (!Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
+ {
+ Task.Run(async () => await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.DownloadImageAsync(msg));
+ }
}
private void resetPresences()
diff --git a/Data_Manager2/Classes/DBManager/DiscoDBManager.cs b/Data_Manager2/Classes/DBManager/DiscoDBManager.cs
index d6b7843a6..5182fa88b 100644
--- a/Data_Manager2/Classes/DBManager/DiscoDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/DiscoDBManager.cs
@@ -1,7 +1,7 @@
using Data_Manager2.Classes.DBTables;
+using Shared.Classes.SQLite;
using System;
using System.Collections.Generic;
-using Thread_Save_Components.Classes.SQLite;
using XMPP_API.Classes;
using XMPP_API.Classes.Network.XML.Messages;
using XMPP_API.Classes.Network.XML.Messages.XEP_0030;
@@ -55,7 +55,7 @@ private void addIdentities(List identities, string from)
{
if (from != null && i.TYPE != null && i.CATEGORY != null)
{
- update(new DiscoIdentityTable()
+ dB.InsertOrReplace(new DiscoIdentityTable()
{
id = DiscoIdentityTable.generateId(from, i.TYPE),
fromServer = from,
@@ -77,7 +77,7 @@ private void addFeatures(List features, string from)
{
if (from != null && f.VAR != null)
{
- update(new DiscoFeatureTable
+ dB.InsertOrReplace(new DiscoFeatureTable
{
id = DiscoFeatureTable.generateId(from, f.VAR),
fromServer = from,
@@ -97,7 +97,7 @@ private void addItems(List items, string from, XMPPClient client, boo
{
if (from != null && i.JID != null)
{
- update(new DiscoItemTable()
+ dB.InsertOrReplace(new DiscoItemTable()
{
id = DiscoItemTable.generateId(from, i.JID),
fromServer = from,
diff --git a/Data_Manager2/Classes/DBManager/ImageDBManager.cs b/Data_Manager2/Classes/DBManager/ImageDBManager.cs
index f48e8699f..61aa6d812 100644
--- a/Data_Manager2/Classes/DBManager/ImageDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/ImageDBManager.cs
@@ -1,14 +1,12 @@
using Data_Manager2.Classes.DBTables;
using Logging;
+using Shared.Classes.Network;
+using Shared.Classes.SQLite;
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Net;
using System.Threading.Tasks;
-using Thread_Save_Components.Classes.SQLite;
using Windows.Storage;
-using Windows.Storage.Search;
namespace Data_Manager2.Classes.DBManager
{
@@ -18,56 +16,25 @@ public class ImageDBManager : AbstractDBManager
#region --Attributes--
public static readonly ImageDBManager INSTANCE = new ImageDBManager();
- // The interval for how often the ImageTable onDownloadProgressChanged() should get triggered (e.g 0.1 = every 10%):
- private const double DOWNLOAD_PROGRESS_REPORT_INTERVAL = 0.05;
-
- // A list of all currently downloading images:
- private readonly List DOWNLOADING;
-
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
- ///
- /// Basic Constructor
- ///
- ///
- /// 15/12/2017 Created [Fabian Sauter]
- ///
- public ImageDBManager()
- {
- DOWNLOADING = new List();
- contiuneAllDownloads();
- }
+
#endregion
//--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
#region --Set-, Get- Methods--
///
- /// Calculates the size of the "cachedImages" folder.
+ ///
///
- /// Returns the "cachedImages" folder size in KB.
- public async Task getCachedImagesFolderSizeAsync()
- {
- StorageFolder f = await getCachedImagesFolderAsync();
- StorageFileQueryResult result = f.CreateFileQuery(CommonFileQuery.OrderByName);
-
- var fileSizeTasks = (await result.GetFilesAsync()).Select(async file => (await file.GetBasicPropertiesAsync()).Size);
- var sizes = await Task.WhenAll(fileSizeTasks);
-
- return sizes.Sum(l => (long)l) / 1024;
- }
-
- ///
- /// Returns the image container from a given ChatMessageTable.
- ///
- /// The ChatMessageTable.
- /// The corresponding image container.
- public ImageTable getImageForMessage(ChatMessageTable msg)
+ ///
+ ///
+ public async Task getImageAsync(ChatMessageTable msg)
{
- ImageTable img = DOWNLOADING.Find(x => string.Equals(x.messageId, msg.id));
+ ImageTable img = (ImageTable)await ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.FindAsync((x) => { return x is ImageTable imageTable && string.Equals(imageTable.messageId, msg.id); });
if (img is null)
{
- List list = dB.Query(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE messageId = ?;", msg.id);
+ List list = dB.Query(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE " + nameof(ImageTable.messageId) + " = ?;", msg.id);
if (list.Count > 0)
{
img = list[0];
@@ -76,309 +43,57 @@ public ImageTable getImageForMessage(ChatMessageTable msg)
return img;
}
- ///
- /// Checks if the image is already available locally, if yes returns the path to it.
- /// Else tries to download the image and stores it. Also returns the path of the downloaded image.
- ///
- /// The image container.
- /// The image url.
- /// Returns the local path to the downloaded image.
- public async Task getImagePathAsync(ImageTable img, string url)
- {
- try
- {
- string fileName = createUniqueFileName(url);
- string path = await getLocalImageAsync(fileName);
- if (path is null)
- {
- path = await downloadImageAsync(img, url, fileName);
- }
- return path;
- }
- catch (Exception e)
- {
- Logger.Error("Error during downloading image: " + e.Message);
- img.errorMessage = e.Message;
- update(img);
- return null;
- }
- }
-
- ///
- /// Returns the path for the given file name if the file exits.
- /// Else returns null.
- ///
- /// The file name.
- /// The path to the file if it exists else null.
- private async Task getLocalImageAsync(string name)
- {
- StorageFolder f = await getCachedImagesFolderAsync();
- if (f != null)
- {
- FileInfo fI = new FileInfo(f.Path + '\\' + name);
- if (fI.Exists)
- {
- return fI.FullName;
- }
- }
- return null;
- }
-
- private async Task getCachedImagesFolderAsync()
+ public void setImage(ImageTable image)
{
- if (Settings.getSettingBoolean(SettingsConsts.DISABLE_DOWNLOAD_IMAGES_TO_LIBARY))
- {
- return await ApplicationData.Current.LocalFolder.CreateFolderAsync("cachedImages", CreationCollisionOption.OpenIfExists);
- }
- return await KnownFolders.PicturesLibrary.CreateFolderAsync("UWPX", CreationCollisionOption.OpenIfExists);
+ dB.InsertOrReplace(image);
}
- ///
- /// Continues all outstanding downloads.
- ///
- private void contiuneAllDownloads()
+ public List getAllUndownloadedImages()
{
- List list = dB.Query(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE state = 0 OR state = 1;");
- foreach (ImageTable img in list)
- {
- Task.Run(async () =>
- {
- // Reset image progress:
- img.progress = 0;
-
- ChatMessageTable msg = ChatDBManager.INSTANCE.getChatMessageById(img.messageId);
- await downloadImageAsync(img, msg.message);
- });
- }
+ return dB.Query(true, "SELECT * FROM " + DBTableConsts.IMAGE_TABLE + " WHERE " + nameof(ImageTable.State) + " != ? AND " + nameof(ImageTable.State) + " != ?;", (int)DownloadState.DONE, (int)DownloadState.ERROR);
}
- ///
- /// Downloads the image from the given message and stores it locally.
- ///
- /// The image container.
- /// The image url.
- ///
- private async Task downloadImageAsync(ImageTable img, string msg)
+ public async Task deleteImageAsync(ChatMessageTable msg)
{
- DOWNLOADING.Add(img);
-
- updateImageState(img, DownloadState.DOWNLOADING);
- string path = await getImagePathAsync(img, msg);
-
- img.path = path;
- if (path is null)
- {
- updateImageState(img, DownloadState.ERROR);
- }
- else
+ ImageTable image = await getImageAsync(msg);
+ if (!(image is null))
{
- updateImageState(img, DownloadState.DONE);
- }
- }
+ // Cancel download:
+ ConnectionHandler.INSTANCE.IMAGE_DOWNLOAD_HANDLER.CancelDownload(image);
- #endregion
- //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
- #region --Misc Methods (Public)--
- ///
- /// Retries to download the image from the given ChatMessageTable.
- ///
- /// The ChatMessageTable containing the image url.
- /// The image container.
- public ImageTable retryImageDownload(ChatMessageTable msg)
- {
- if (msg.isImage)
- {
- ImageTable img = getImageForMessage(msg);
- if (img is null)
+ // Try to delete local file:
+ try
{
- img = new ImageTable()
+ if (!string.IsNullOrEmpty(image.TargetFolderPath) && !string.IsNullOrEmpty(image.TargetFileName))
{
- messageId = msg.id,
- path = null,
- state = DownloadState.WAITING,
- progress = 0
- };
+ string path = Path.Combine(image.TargetFolderPath, image.TargetFileName);
+ StorageFile file = await StorageFile.GetFileFromPathAsync(path);
+ if (!(file is null))
+ {
+ await file.DeleteAsync();
+ }
+ }
+ Logger.Info("Deleted: " + image.TargetFileName);
}
- else
+ catch (Exception e)
{
- img.state = DownloadState.WAITING;
- img.progress = 0;
- img.path = null;
+ Logger.Error("Failed to delete image: " + image.TargetFileName, e);
}
- Task.Run(async () =>
- {
- update(img);
- await downloadImageAsync(img, msg.message);
- });
-
- return img;
- }
- return null;
- }
-
- ///
- /// Deletes the "cachedImages" folder and creates a new empty one.
- ///
- public async Task deleteImageCacheAsync()
- {
- StorageFolder folder = await getCachedImagesFolderAsync();
- if (folder != null)
- {
- await folder.DeleteAsync();
+ // Delete DB entry:
+ dB.Delete(image);
}
- await getCachedImagesFolderAsync();
- Logger.Info("Deleted image cache!");
}
- ///
- /// Opens the current folder containing the cached images.
- ///
- public async Task openCachedImagesFolderAsync()
- {
- StorageFolder folder = await getCachedImagesFolderAsync();
- await Windows.System.Launcher.LaunchFolderAsync(folder);
- }
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
- ///
- /// Creates a new task, downloads the image from the given message and stores it locally.
- ///
- /// The ChatMessageTable containing the image url.
- public void downloadImage(ChatMessageTable msg)
- {
- if (msg.isImage)
- {
- Task.Run(async () =>
- {
- ImageTable img = new ImageTable()
- {
- messageId = msg.id,
- path = null,
- state = DownloadState.WAITING,
- progress = 0
- };
- update(img);
- await downloadImageAsync(img, msg.message);
- });
- }
- }
#endregion
#region --Misc Methods (Private)--
- ///
- /// Tries to download the image from the given url.
- ///
- /// The image url.
- ///
- /// Returns null if it fails, else the local path.
- private async Task downloadImageAsync(ImageTable img, string url, string name)
- {
- Logger.Info("Started downloading image <" + name + "> from: " + url);
- HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
- HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
- long bytesReadTotal = 0;
- double lastProgressUpdatePercent = 0;
-
- // Check that the remote file was found. The ContentType
- // check is performed since a request for a non-existent
- // image file might be redirected to a 404-page, which would
- // yield the StatusCode "OK", even though the image was not
- // found.
- if (response.StatusCode == HttpStatusCode.OK ||
- response.StatusCode == HttpStatusCode.Moved ||
- response.StatusCode == HttpStatusCode.Redirect)
- {
- // if the remote file was found, download it
- StorageFile f = await createImageStorageFileAsync(name);
- using (Stream inputStream = response.GetResponseStream())
- using (Stream outputStream = await f.OpenStreamForWriteAsync())
- {
- byte[] buffer = new byte[4096];
- int bytesRead;
- do
- {
- bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length);
- await outputStream.WriteAsync(buffer, 0, bytesRead);
- // Update progress:
- bytesReadTotal += bytesRead;
- lastProgressUpdatePercent = updateProgress(img, response.ContentLength, bytesReadTotal, lastProgressUpdatePercent);
-
- } while (bytesRead != 0);
- }
- Logger.Info("Finished downloading image <" + name + "> from: " + url);
- return f.Path;
- }
- else
- {
- img.errorMessage = "Status code check failed: " + response.StatusCode + " (" + response.StatusDescription + ')';
- update(img);
- }
- Logger.Error("Unable to download image <" + name + "> from: " + url + " Status code: " + response.StatusCode);
- return null;
- }
-
- ///
- /// Updates the progress of the given ImageTable and triggers if necessary the onDownloadProgressChanged event.
- ///
- /// The image container.
- /// The total length of the download in bytes.
- /// How many bytes got read already?
- /// When was the last onDownloadProgressChanged event triggered?
- /// Returns the last progress update percentage.
- private double updateProgress(ImageTable img, long totalLengt, long bytesReadTotal, double lastProgressUpdatePercent)
- {
- img.progress = ((double)bytesReadTotal) / ((double)totalLengt);
- if ((img.progress - lastProgressUpdatePercent) >= DOWNLOAD_PROGRESS_REPORT_INTERVAL)
- {
- img.onDownloadProgressChanged();
- return img.progress;
- }
-
- return lastProgressUpdatePercent;
- }
-
- private async Task createImageStorageFileAsync(string name)
- {
- StorageFolder f = await getCachedImagesFolderAsync();
- return await f.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting);
- }
-
- ///
- /// Creates an unique file name, bases on the given url and the current time.
- ///
- /// The url of the image.
- /// Returns an unique file name.
- private string createUniqueFileName(string url)
- {
- string name = DateTime.Now.ToString("dd.MM.yyyy_HH.mm.ss.ffff");
- int index = url.LastIndexOf('.');
- string ending = url.Substring(index, url.Length - index);
- return name + ending;
- }
-
- ///
- /// Updates the DownloadState of the given ImageTable and triggers the onStateChanged() event.
- ///
- /// The ImageTable, that should get updated.
- /// The new DownloadState.
- private void updateImageState(ImageTable img, DownloadState state)
- {
- img.state = state;
- img.onStateChanged();
- update(img);
- switch (state)
- {
- case DownloadState.DONE:
- case DownloadState.ERROR:
- DOWNLOADING.Remove(img);
- break;
-
- default:
- break;
- }
- }
#endregion
diff --git a/Data_Manager2/Classes/DBManager/MUCDBManager.cs b/Data_Manager2/Classes/DBManager/MUCDBManager.cs
index c52cab3f2..5e9c8d4ba 100644
--- a/Data_Manager2/Classes/DBManager/MUCDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/MUCDBManager.cs
@@ -1,8 +1,8 @@
-using Data_Manager2.Classes.Events;
-using Data_Manager2.Classes.DBTables;
+using Data_Manager2.Classes.DBTables;
+using Data_Manager2.Classes.Events;
+using Shared.Classes.SQLite;
using System.Collections.Generic;
using XMPP_API.Classes.Network.XML.Messages.XEP_0048;
-using Thread_Save_Components.Classes.SQLite;
namespace Data_Manager2.Classes.DBManager
{
@@ -74,7 +74,7 @@ public void setMUCOccupant(MUCOccupantTable occupant, bool delete, bool triggerM
}
else
{
- update(occupant);
+ dB.InsertOrReplace(occupant);
if (triggerMUCOccupantChanged)
{
@@ -122,7 +122,7 @@ public void setMUCChatInfo(MUCChatInfoTable info, bool delete, bool triggerMUCCh
}
else
{
- update(info);
+ dB.InsertOrReplace(info);
}
if (triggerMUCChanged)
diff --git a/Data_Manager2/Classes/DBManager/Omemo/OmemoDeviceDBManager.cs b/Data_Manager2/Classes/DBManager/Omemo/OmemoDeviceDBManager.cs
index 400777a1c..65ffd19c4 100644
--- a/Data_Manager2/Classes/DBManager/Omemo/OmemoDeviceDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/Omemo/OmemoDeviceDBManager.cs
@@ -1,9 +1,9 @@
using Data_Manager2.Classes.DBTables;
using Data_Manager2.Classes.DBTables.Omemo;
using libsignal;
+using Shared.Classes.SQLite;
using System;
using System.Collections.Generic;
-using Thread_Save_Components.Classes.SQLite;
using XMPP_API.Classes.Network.XML.Messages.XEP_0384;
namespace Data_Manager2.Classes.DBManager.Omemo
diff --git a/Data_Manager2/Classes/DBManager/Omemo/OmemoSignalKeyDBManager.cs b/Data_Manager2/Classes/DBManager/Omemo/OmemoSignalKeyDBManager.cs
index 4a35c6724..04a654dbc 100644
--- a/Data_Manager2/Classes/DBManager/Omemo/OmemoSignalKeyDBManager.cs
+++ b/Data_Manager2/Classes/DBManager/Omemo/OmemoSignalKeyDBManager.cs
@@ -2,8 +2,8 @@
using Data_Manager2.Classes.DBTables.Omemo;
using libsignal;
using libsignal.state;
+using Shared.Classes.SQLite;
using System.Collections.Generic;
-using Thread_Save_Components.Classes.SQLite;
namespace Data_Manager2.Classes.DBManager.Omemo
{
diff --git a/Data_Manager2/Classes/DBManager/SpamDBManager.cs b/Data_Manager2/Classes/DBManager/SpamDBManager.cs
new file mode 100644
index 000000000..5c1042d72
--- /dev/null
+++ b/Data_Manager2/Classes/DBManager/SpamDBManager.cs
@@ -0,0 +1,116 @@
+using Data_Manager2.Classes.DBTables;
+using Logging;
+using Shared.Classes.SQLite;
+using SQLite;
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace Data_Manager2.Classes.DBManager
+{
+ public class SpamDBManager : AbstractDBManager
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ public static readonly SpamDBManager INSTANCE = new SpamDBManager();
+
+ public const string DEFAULT_SPAM_REGEX = @"\p{IsCyrillic}";
+ private Regex spamRegex = null;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+ public bool isSpam(string text)
+ {
+ if(!(spamRegex is null))
+ {
+ return !(getSpam(text) is null) || spamRegex.IsMatch(text);
+ }
+ return !(getSpam(text) is null);
+ }
+
+ public SpamMessageTable getSpam(string text)
+ {
+ SQLiteCommand cmd = dB.CreateCommand("SELECT * FROM " + DBTableConsts.SPAM_MESSAGE_TABLE + " WHERE text LIKE @TEXT;");
+ cmd.Bind("@TEXT", '%' + text + '%');
+ List result = dB.ExecuteCommand(true, cmd);
+ if (result.Count > 0)
+ {
+ return result[0];
+ }
+ return null;
+ }
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ public void addSpamMessage(string text, DateTime dateTime)
+ {
+ SpamMessageTable spam = getSpam(text);
+ if(spam is null)
+ {
+ spam = new SpamMessageTable
+ {
+ lastReceived = dateTime,
+ text = text,
+ count = 1,
+ };
+ }
+ else
+ {
+ spam.count++;
+ spam.lastReceived = dateTime;
+ }
+ dB.InsertOrReplace(spam);
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+ protected override void createTables()
+ {
+ dB.CreateTable();
+ }
+
+ protected override void dropTables()
+ {
+ dB.DropTable();
+ }
+
+ public override void initManager()
+ {
+ string regex = Settings.getSettingString(SettingsConsts.SPAM_REGEX, DEFAULT_SPAM_REGEX);
+ updateSpamRegex(regex);
+ }
+
+ public void updateSpamRegex(string regex)
+ {
+ try
+ {
+ spamRegex = new Regex(regex);
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Failed to create spam regular expression for: " + regex, e);
+ spamRegex = null;
+ }
+ }
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Data_Manager2/Classes/DBTables/AccountTable.cs b/Data_Manager2/Classes/DBTables/AccountTable.cs
index b10546fec..e5429a6e4 100644
--- a/Data_Manager2/Classes/DBTables/AccountTable.cs
+++ b/Data_Manager2/Classes/DBTables/AccountTable.cs
@@ -1,7 +1,6 @@
using SQLite;
-using XMPP_API.Classes.Network;
using XMPP_API.Classes;
-using XMPP_API.Classes.Network.XML.Messages.XEP_0384;
+using XMPP_API.Classes.Network;
namespace Data_Manager2.Classes.DBTables
{
@@ -63,10 +62,10 @@ public AccountTable()
public AccountTable(XMPPAccount account)
{
- this.id = account.getIdAndDomain();
- this.userId = account.user.userId;
- this.domain = account.user.domain;
- this.resource = account.user.resource;
+ this.id = account.getBareJid();
+ this.userId = account.user.localPart;
+ this.domain = account.user.domainPart;
+ this.resource = account.user.resourcePart;
this.serverAddress = account.serverAddress;
this.port = account.port;
this.disabled = account.disabled;
@@ -82,8 +81,10 @@ public AccountTable(XMPPAccount account)
internal XMPPAccount toXMPPAccount()
{
- return new XMPPAccount(new XMPPUser(userId, domain, resource), serverAddress, port)
+ return new XMPPAccount(new XMPPUser(userId, domain, resource))
{
+ serverAddress = serverAddress,
+ port = port,
color = color,
presencePriorety = presencePriorety,
disabled = disabled,
diff --git a/Data_Manager2/Classes/DBTables/ChatTable.cs b/Data_Manager2/Classes/DBTables/ChatTable.cs
index d95c3f441..e1f120d68 100644
--- a/Data_Manager2/Classes/DBTables/ChatTable.cs
+++ b/Data_Manager2/Classes/DBTables/ChatTable.cs
@@ -33,7 +33,7 @@ public class ChatTable : IComparable
// online, dnd, xa, ...
public Presence presence { get; set; }
[Ignore]
- // The state of the chat (XEP-0083) - only interesting during runtime
+ // The state of the chat (XEP-0085) - only interesting during runtime
public string chatState { get; set; }
[NotNull]
// The type of the chat e.g. MUC/MIX/...
@@ -63,7 +63,7 @@ public ChatTable(string chatJabberId, string userAccountId)
this.chatType = ChatType.CHAT;
this.inRoster = false;
this.muted = false;
- this.omemoEnabled = false;
+ this.omemoEnabled = Settings.getSettingBoolean(SettingsConsts.ENABLE_OMEMO_BY_DEFAULT_FOR_NEW_CHATS);
this.presence = Presence.Unavailable;
this.status = null;
this.subscription = null;
diff --git a/Data_Manager2/Classes/DBTables/DBTableConsts.cs b/Data_Manager2/Classes/DBTables/DBTableConsts.cs
index 6944ff4ef..455185d0f 100644
--- a/Data_Manager2/Classes/DBTables/DBTableConsts.cs
+++ b/Data_Manager2/Classes/DBTables/DBTableConsts.cs
@@ -8,12 +8,13 @@ static class DBTableConsts
public const string DISCO_FEATURE_TABLE = "DiscoFeatureTable";
public const string DISCO_IDENTITY_TABLE = "DiscoIdentityTable";
public const string DISCO_ITEM_TABLE = "DiscoItemTable";
- public const string IMAGE_TABLE = "ImageTable";
+ public const string IMAGE_TABLE = "ImageTable_2";
public const string MUC_CHAT_INFO_TABLE = "MUCChatInfoTable_3";
public const string MUC_OCCUPANT_TABLE = "MUCOccupantTable";
public const string MUC_DIRECT_INVITATION_TABLE = "MUCDirectInvitationTable";
public const string IGNORED_CERTIFICATE_ERROR_TABLE = "IgnoredCertificateErrorTable";
public const string CONNECTION_OPTIONS_TABLE = "ConnectionOptionsTable_2";
+ public const string SPAM_MESSAGE_TABLE = "SpamMessageTable";
public const string OMEMO_SIGNED_PRE_KEY_TABLE = "OmemoSignedPreKeyTable";
public const string OMEMO_PRE_KEY_TABLE = "OmemoPreKeyTable";
diff --git a/Data_Manager2/Classes/DBTables/ImageTable.cs b/Data_Manager2/Classes/DBTables/ImageTable.cs
index cdd38804b..dac44a2ae 100644
--- a/Data_Manager2/Classes/DBTables/ImageTable.cs
+++ b/Data_Manager2/Classes/DBTables/ImageTable.cs
@@ -1,49 +1,21 @@
-using Data_Manager2.Classes.Events;
+using Shared.Classes.Network;
using SQLite;
-using System.Threading.Tasks;
-using Windows.Storage;
-using Windows.UI.Xaml.Media.Imaging;
-using System;
namespace Data_Manager2.Classes.DBTables
{
[Table(DBTableConsts.IMAGE_TABLE)]
- public class ImageTable
+ public class ImageTable : AbstractDownloadableObject
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
[PrimaryKey]
// The id of the message:
public string messageId { get; set; }
- // The local path:
- public string path { get; set; }
- // The state of the image download:
- public DownloadState state { get; set; }
- // If the image download failed:
- public string errorMessage { get; set; }
-
- // The image download progress:
- [Ignore]
- public double progress { get; set; }
-
- public delegate void DownloadStateChangedHandler(ImageTable img, DownloadStateChangedEventArgs args);
- public delegate void DownloadProgressChangedHandler(ImageTable img, DownloadProgressChangedEventArgs args);
-
- public event DownloadStateChangedHandler DownloadStateChanged;
- public event DownloadProgressChangedHandler DownloadProgressChanged;
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
- ///
- /// Basic Constructor
- ///
- ///
- /// 17/11/2017 Created [Fabian Sauter]
- ///
- public ImageTable()
- {
- }
+
#endregion
//--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
@@ -53,45 +25,7 @@ public ImageTable()
#endregion
//--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
#region --Misc Methods (Public)--
- public void onStateChanged()
- {
- DownloadStateChanged?.Invoke(this, new DownloadStateChangedEventArgs(state));
- }
-
- public void onDownloadProgressChanged()
- {
- DownloadProgressChanged?.Invoke(this, new DownloadProgressChangedEventArgs(progress));
- }
-
- ///
- /// Converts the path to an BitmapImage.
- /// This is a workaround to open also images that are stored on a separate drive.
- ///
- /// The BitmapImage representation of the current path object.
- public async Task getBitmapImageAsync()
- {
- if(path is null)
- {
- return null;
- }
-
- try
- {
- StorageFile file = await StorageFile.GetFileFromPathAsync(path);
- if(file is null)
- {
- return null;
- }
-
- BitmapImage img = new BitmapImage();
- img.SetSource(await file.OpenReadAsync());
- return img;
- }
- catch (Exception)
- {
- return null;
- }
- }
+
#endregion
diff --git a/Data_Manager2/Classes/DBTables/SpamMessageTable.cs b/Data_Manager2/Classes/DBTables/SpamMessageTable.cs
new file mode 100644
index 000000000..865999533
--- /dev/null
+++ b/Data_Manager2/Classes/DBTables/SpamMessageTable.cs
@@ -0,0 +1,49 @@
+using SQLite;
+using System;
+
+namespace Data_Manager2.Classes.DBTables
+{
+ [Table(DBTableConsts.SPAM_MESSAGE_TABLE)]
+ public class SpamMessageTable
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ [AutoIncrement, PrimaryKey]
+ public int id { get; set; }
+ public DateTime lastReceived { get; set; }
+ public int count { get; set; }
+ public string text { get; set; }
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Data_Manager2/Classes/DownloadState.cs b/Data_Manager2/Classes/DownloadState.cs
deleted file mode 100644
index 24e7b8001..000000000
--- a/Data_Manager2/Classes/DownloadState.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Data_Manager2.Classes
-{
- public enum DownloadState
- {
- WAITING,
- DOWNLOADING,
- DONE,
- ERROR
- }
-}
diff --git a/Data_Manager2/Classes/Events/ChatMessageChangedEventArgs.cs b/Data_Manager2/Classes/Events/ChatMessageChangedEventArgs.cs
index d5705a793..23b01a930 100644
--- a/Data_Manager2/Classes/Events/ChatMessageChangedEventArgs.cs
+++ b/Data_Manager2/Classes/Events/ChatMessageChangedEventArgs.cs
@@ -8,6 +8,7 @@ public class ChatMessageChangedEventArgs : EventArgs
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
public readonly ChatMessageTable MESSAGE;
+ public readonly bool REMOVED;
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
@@ -18,9 +19,10 @@ public class ChatMessageChangedEventArgs : EventArgs
///
/// 01/01/2018 Created [Fabian Sauter]
///
- public ChatMessageChangedEventArgs(ChatMessageTable message)
+ public ChatMessageChangedEventArgs(ChatMessageTable message, bool removed)
{
this.MESSAGE = message;
+ this.REMOVED = removed;
}
#endregion
diff --git a/Data_Manager2/Classes/ImageDownloadHandler.cs b/Data_Manager2/Classes/ImageDownloadHandler.cs
new file mode 100644
index 000000000..c1408c1ec
--- /dev/null
+++ b/Data_Manager2/Classes/ImageDownloadHandler.cs
@@ -0,0 +1,155 @@
+using Data_Manager2.Classes.DBManager;
+using Data_Manager2.Classes.DBTables;
+using Logging;
+using Shared.Classes.Network;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Windows.Storage;
+
+namespace Data_Manager2.Classes
+{
+ public class ImageDownloadHandler
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ private readonly DownloadHandler DOWNLOAD_HANDLER;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+ public ImageDownloadHandler(DownloadHandler downloadHandler)
+ {
+ this.DOWNLOAD_HANDLER = downloadHandler;
+ this.DOWNLOAD_HANDLER.DownloadStateChanged += DOWNLOAD_HANDLER_DownloadStateChanged;
+ }
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+ public async Task GetImageCacheFolderAsync()
+ {
+ if (Settings.getSettingBoolean(SettingsConsts.DISABLE_DOWNLOAD_IMAGES_TO_LIBARY))
+ {
+ return await ApplicationData.Current.LocalFolder.CreateFolderAsync("cachedImages", CreationCollisionOption.OpenIfExists);
+ }
+ return await KnownFolders.PicturesLibrary.CreateFolderAsync("UWPX", CreationCollisionOption.OpenIfExists);
+ }
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ public async Task DownloadImageAsync(ImageTable image)
+ {
+ if (image.State != DownloadState.DOWNLOADING && image.State != DownloadState.QUEUED)
+ {
+ await DOWNLOAD_HANDLER.EnqueueDownloadAsync(image);
+ }
+ }
+
+ public async Task DownloadImageAsync(ChatMessageTable msg)
+ {
+ ImageTable image = await ImageDBManager.INSTANCE.getImageAsync(msg);
+ if (image is null)
+ {
+ StorageFolder folder = await GetImageCacheFolderAsync();
+ image = new ImageTable()
+ {
+ messageId = msg.id,
+ SourceUrl = msg.message,
+ TargetFileName = CreateUniqueFileName(msg.message),
+ TargetFolderPath = folder.Path,
+ State = DownloadState.NOT_QUEUED,
+ Progress = 0,
+ };
+ ImageDBManager.INSTANCE.setImage(image);
+ }
+ await DownloadImageAsync(image);
+ return image;
+ }
+
+ public async Task RedownloadImageAsync(ImageTable image)
+ {
+ await DOWNLOAD_HANDLER.EnqueueDownloadAsync(image);
+ }
+
+ public void CancelDownload(ImageTable image)
+ {
+ DOWNLOAD_HANDLER.CancelDownload(image);
+ }
+
+ public async Task FindAsync(Predicate predicate)
+ {
+ return await DOWNLOAD_HANDLER.FindAsync(predicate);
+ }
+
+ public async Task ContinueDownloadsAsync()
+ {
+ if (!Settings.getSettingBoolean(SettingsConsts.DISABLE_IMAGE_AUTO_DOWNLOAD))
+ {
+ List images = ImageDBManager.INSTANCE.getAllUndownloadedImages();
+ foreach (ImageTable image in images)
+ {
+ if (image.State == DownloadState.DOWNLOADING || image.State == DownloadState.QUEUED)
+ {
+ image.State = DownloadState.NOT_QUEUED;
+ ImageDBManager.INSTANCE.setImage(image);
+ }
+ await DownloadImageAsync(image);
+ }
+ }
+ }
+
+ public async Task ClearImageCacheAsync()
+ {
+ StorageFolder folder = await GetImageCacheFolderAsync();
+ if (folder != null)
+ {
+ await folder.DeleteAsync();
+ }
+ // Recreate the image cache folder:
+ await GetImageCacheFolderAsync();
+ Logger.Info("Image cache cleared!");
+ }
+
+ public async Task OpenImageCacheFolderAsync()
+ {
+ StorageFolder folder = await GetImageCacheFolderAsync();
+ await Windows.System.Launcher.LaunchFolderAsync(folder);
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+ ///
+ /// Creates an unique file name, bases on the given url and the current time.
+ ///
+ /// The url of the image.
+ /// Returns an unique file name.
+ private string CreateUniqueFileName(string url)
+ {
+ string name = DateTime.Now.ToString("dd.MM.yyyy_HH.mm.ss.ffff");
+ int index = url.LastIndexOf('.');
+ string ending = url.Substring(index, url.Length - index);
+ return name + ending;
+ }
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+ private void DOWNLOAD_HANDLER_DownloadStateChanged(AbstractDownloadableObject o, DownloadStateChangedEventArgs args)
+ {
+ if (o is ImageTable image)
+ {
+ ImageDBManager.INSTANCE.setImage(image);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Data_Manager2/Classes/MUCHandler.cs b/Data_Manager2/Classes/MUCHandler.cs
index a26e25e99..66eceef0b 100644
--- a/Data_Manager2/Classes/MUCHandler.cs
+++ b/Data_Manager2/Classes/MUCHandler.cs
@@ -1,9 +1,9 @@
using Data_Manager2.Classes.DBManager;
using Data_Manager2.Classes.DBTables;
using Logging;
+using Shared.Classes.Collections;
using System;
using System.Threading.Tasks;
-using Thread_Save_Components.Classes.Collections;
using XMPP_API.Classes;
using XMPP_API.Classes.Network.XML.Messages;
using XMPP_API.Classes.Network.XML.Messages.XEP_0045;
@@ -50,11 +50,11 @@ public void onClientConnected(XMPPClient client)
client.NewValidMessage -= Client_NewValidMessage;
client.NewValidMessage += Client_NewValidMessage;
- MUCDBManager.INSTANCE.resetMUCState(client.getXMPPAccount().getIdAndDomain(), true);
+ MUCDBManager.INSTANCE.resetMUCState(client.getXMPPAccount().getBareJid(), true);
if (!Settings.getSettingBoolean(SettingsConsts.DISABLE_AUTO_JOIN_MUC))
{
- Logger.Info("Entering all MUC rooms for '" + client.getXMPPAccount().getIdAndDomain() + '\'');
+ Logger.Info("Entering all MUC rooms for '" + client.getXMPPAccount().getBareJid() + '\'');
enterAllMUCs(client);
}
}
@@ -68,7 +68,7 @@ public void onClientDisconnecting(XMPPClient client)
{
client.NewMUCMemberPresenceMessage -= C_NewMUCMemberPresenceMessage;
client.NewValidMessage -= Client_NewValidMessage;
- MUCDBManager.INSTANCE.resetMUCState(client.getXMPPAccount().getIdAndDomain(), true);
+ MUCDBManager.INSTANCE.resetMUCState(client.getXMPPAccount().getBareJid(), true);
}
public void onMUCRoomSubjectMessage(MUCRoomSubjectMessage mucRoomSubject)
@@ -113,7 +113,7 @@ private void stopMUCJoinHelper(ChatTable muc)
private async Task sendMUCLeaveMessageAsync(XMPPClient client, ChatTable muc, MUCChatInfoTable info)
{
- string from = client.getXMPPAccount().getIdDomainAndResource();
+ string from = client.getXMPPAccount().getFullJid();
string to = muc.chatJabberId + '/' + info.nickname;
LeaveRoomMessage msg = new LeaveRoomMessage(from, to);
await client.sendAsync(msg, false);
@@ -123,7 +123,7 @@ private void enterAllMUCs(XMPPClient client)
{
Task.Run(async () =>
{
- foreach (ChatTable muc in ChatDBManager.INSTANCE.getAllMUCs(client.getXMPPAccount().getIdAndDomain()))
+ foreach (ChatTable muc in ChatDBManager.INSTANCE.getAllMUCs(client.getXMPPAccount().getBareJid()))
{
MUCChatInfoTable info = MUCDBManager.INSTANCE.getMUCInfo(muc.id);
if (info is null)
@@ -150,7 +150,7 @@ private async Task onMUCErrorMessageAsync(XMPPClient client, MUCErrorMessage err
string room = Utils.getBareJidFromFullJid(errorMessage.getFrom());
if (room != null)
{
- string chatId = ChatTable.generateId(room, client.getXMPPAccount().getIdAndDomain());
+ string chatId = ChatTable.generateId(room, client.getXMPPAccount().getBareJid());
ChatTable muc = ChatDBManager.INSTANCE.getChat(chatId);
if (muc != null)
{
@@ -243,7 +243,7 @@ private void C_NewMUCMemberPresenceMessage(XMPPClient client, XMPP_API.Classes.N
{
return;
}
- string chatId = ChatTable.generateId(roomJid, client.getXMPPAccount().getIdAndDomain());
+ string chatId = ChatTable.generateId(roomJid, client.getXMPPAccount().getBareJid());
MUCOccupantTable member = MUCDBManager.INSTANCE.getMUCOccupant(chatId, msg.FROM_NICKNAME);
if (member is null)
diff --git a/Data_Manager2/Classes/MUCJoinHelper.cs b/Data_Manager2/Classes/MUCJoinHelper.cs
index 8a27fc54e..d19c4add4 100644
--- a/Data_Manager2/Classes/MUCJoinHelper.cs
+++ b/Data_Manager2/Classes/MUCJoinHelper.cs
@@ -1,9 +1,9 @@
using Data_Manager2.Classes.DBManager;
using Data_Manager2.Classes.DBTables;
using Logging;
+using Shared.Classes.Collections;
using System;
using System.Threading.Tasks;
-using Thread_Save_Components.Classes.Collections;
using XMPP_API.Classes;
using XMPP_API.Classes.Network.XML.Messages.XEP_0045;
@@ -47,7 +47,7 @@ public MUCJoinHelper(XMPPClient client, ChatTable muc, MUCChatInfoTable info)
#region --Misc Methods (Public)--
public async Task requestReservedNicksAsync()
{
- DiscoReservedRoomNicknamesMessages msg = new DiscoReservedRoomNicknamesMessages(CLIENT.getXMPPAccount().getIdDomainAndResource(), MUC.chatJabberId);
+ DiscoReservedRoomNicknamesMessages msg = new DiscoReservedRoomNicknamesMessages(CLIENT.getXMPPAccount().getFullJid(), MUC.chatJabberId);
await CLIENT.sendAsync(msg, false);
}
@@ -61,7 +61,7 @@ public async Task enterRoomAsync()
MUCDBManager.INSTANCE.deleteAllOccupantsforChat(MUC.id);
// Create message:
- JoinRoomRequestMessage msg = new JoinRoomRequestMessage(CLIENT.getXMPPAccount().getIdDomainAndResource(), MUC.chatJabberId, INFO.nickname, INFO.password);
+ JoinRoomRequestMessage msg = new JoinRoomRequestMessage(CLIENT.getXMPPAccount().getFullJid(), MUC.chatJabberId, INFO.nickname, INFO.password);
// Subscribe to events for receiving answers:
CLIENT.NewMUCMemberPresenceMessage -= CLIENT_NewMUCMemberPresenceMessage;
diff --git a/Data_Manager2/Classes/Omemo/OmemoStore.cs b/Data_Manager2/Classes/Omemo/OmemoStore.cs
index b0fefe298..4f5ff7f90 100644
--- a/Data_Manager2/Classes/Omemo/OmemoStore.cs
+++ b/Data_Manager2/Classes/Omemo/OmemoStore.cs
@@ -52,7 +52,7 @@ public bool IsTrustedIdentity(string name, IdentityKey identityKey)
public List GetSubDeviceSessions(string name)
{
- return OmemoSignalKeyDBManager.INSTANCE.getDeviceIds(name, ACCOUNT.getIdAndDomain());
+ return OmemoSignalKeyDBManager.INSTANCE.getDeviceIds(name, ACCOUNT.getBareJid());
}
#endregion
@@ -60,19 +60,19 @@ public List GetSubDeviceSessions(string name)
#region --Misc Methods (Public)--
public bool SaveIdentity(string name, IdentityKey identityKey)
{
- bool contains = OmemoSignalKeyDBManager.INSTANCE.containsIdentityKey(name, ACCOUNT.getIdAndDomain());
- OmemoSignalKeyDBManager.INSTANCE.setIdentityKey(name, identityKey, ACCOUNT.getIdAndDomain());
+ bool contains = OmemoSignalKeyDBManager.INSTANCE.containsIdentityKey(name, ACCOUNT.getBareJid());
+ OmemoSignalKeyDBManager.INSTANCE.setIdentityKey(name, identityKey, ACCOUNT.getBareJid());
return contains;
}
public bool ContainsPreKey(uint preKeyId)
{
- return OmemoSignalKeyDBManager.INSTANCE.containsPreKeyRecord(preKeyId, ACCOUNT.getIdAndDomain());
+ return OmemoSignalKeyDBManager.INSTANCE.containsPreKeyRecord(preKeyId, ACCOUNT.getBareJid());
}
public PreKeyRecord LoadPreKey(uint preKeyId)
{
- PreKeyRecord preKeyRecord = OmemoSignalKeyDBManager.INSTANCE.getPreKeyRecord(preKeyId, ACCOUNT.getIdAndDomain());
+ PreKeyRecord preKeyRecord = OmemoSignalKeyDBManager.INSTANCE.getPreKeyRecord(preKeyId, ACCOUNT.getBareJid());
if (preKeyRecord is null)
{
throw new InvalidKeyIdException("No such key: " + preKeyId);
@@ -82,17 +82,17 @@ public PreKeyRecord LoadPreKey(uint preKeyId)
public void RemovePreKey(uint preKeyId)
{
- OmemoSignalKeyDBManager.INSTANCE.deletePreKey(preKeyId, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deletePreKey(preKeyId, ACCOUNT.getBareJid());
}
public void StorePreKey(uint preKeyId, PreKeyRecord preKey)
{
- OmemoSignalKeyDBManager.INSTANCE.setPreKey(preKeyId, preKey, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setPreKey(preKeyId, preKey, ACCOUNT.getBareJid());
}
public bool ContainsSession(SignalProtocolAddress address)
{
- SessionRecord session = OmemoSignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getIdAndDomain());
+ SessionRecord session = OmemoSignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getBareJid());
return session != null && session.getSessionState().hasSenderChain() && session.getSessionState().getSessionVersion() == CiphertextMessage.CURRENT_VERSION;
}
@@ -103,12 +103,12 @@ public void DeleteAllSessions(string name)
public void DeleteSession(SignalProtocolAddress address)
{
- OmemoSignalKeyDBManager.INSTANCE.deleteSession(address, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deleteSession(address, ACCOUNT.getBareJid());
}
public SessionRecord LoadSession(SignalProtocolAddress address)
{
- SessionRecord session = OmemoSignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getIdAndDomain());
+ SessionRecord session = OmemoSignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getBareJid());
if (session is null)
{
Logger.Warn("No existing libsignal session found for: " + address.ToString());
@@ -119,17 +119,17 @@ public SessionRecord LoadSession(SignalProtocolAddress address)
public void StoreSession(SignalProtocolAddress address, SessionRecord record)
{
- OmemoSignalKeyDBManager.INSTANCE.setSession(address, record, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setSession(address, record, ACCOUNT.getBareJid());
}
public bool ContainsSignedPreKey(uint signedPreKeyId)
{
- return OmemoSignalKeyDBManager.INSTANCE.containsSignedPreKey(signedPreKeyId, ACCOUNT.getIdAndDomain());
+ return OmemoSignalKeyDBManager.INSTANCE.containsSignedPreKey(signedPreKeyId, ACCOUNT.getBareJid());
}
public SignedPreKeyRecord LoadSignedPreKey(uint signedPreKeyId)
{
- SignedPreKeyRecord signedPreKeyRecord = OmemoSignalKeyDBManager.INSTANCE.getSignedPreKey(signedPreKeyId, ACCOUNT.getIdAndDomain());
+ SignedPreKeyRecord signedPreKeyRecord = OmemoSignalKeyDBManager.INSTANCE.getSignedPreKey(signedPreKeyId, ACCOUNT.getBareJid());
if (signedPreKeyRecord is null)
{
throw new InvalidKeyIdException("No such key: " + signedPreKeyId);
@@ -139,52 +139,52 @@ public SignedPreKeyRecord LoadSignedPreKey(uint signedPreKeyId)
public List LoadSignedPreKeys()
{
- return OmemoSignalKeyDBManager.INSTANCE.getAllSignedPreKeys(ACCOUNT.getIdAndDomain());
+ return OmemoSignalKeyDBManager.INSTANCE.getAllSignedPreKeys(ACCOUNT.getBareJid());
}
public void RemoveSignedPreKey(uint signedPreKeyId)
{
- OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(signedPreKeyId, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.deleteSignedPreKey(signedPreKeyId, ACCOUNT.getBareJid());
}
public void StoreSignedPreKey(uint signedPreKeyId, SignedPreKeyRecord signedPreKey)
{
- OmemoSignalKeyDBManager.INSTANCE.setSignedPreKey(signedPreKeyId, signedPreKey, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setSignedPreKey(signedPreKeyId, signedPreKey, ACCOUNT.getBareJid());
}
public IList LoadPreKeys()
{
- return OmemoSignalKeyDBManager.INSTANCE.getAllPreKeys(ACCOUNT.getIdAndDomain());
+ return OmemoSignalKeyDBManager.INSTANCE.getAllPreKeys(ACCOUNT.getBareJid());
}
public void StorePreKeys(IList preKeys)
{
- OmemoSignalKeyDBManager.INSTANCE.setPreKeys(preKeys, ACCOUNT.getIdAndDomain());
+ OmemoSignalKeyDBManager.INSTANCE.setPreKeys(preKeys, ACCOUNT.getBareJid());
}
public void StoreDevices(IList devices)
{
- OmemoDeviceDBManager.INSTANCE.setDevices(devices, ACCOUNT.getIdAndDomain());
+ OmemoDeviceDBManager.INSTANCE.setDevices(devices, ACCOUNT.getBareJid());
}
public void StoreDevice(SignalProtocolAddress device)
{
- OmemoDeviceDBManager.INSTANCE.setDevice(device, ACCOUNT.getIdAndDomain());
+ OmemoDeviceDBManager.INSTANCE.setDevice(device, ACCOUNT.getBareJid());
}
public IList LoadDevices(string name)
{
- return OmemoDeviceDBManager.INSTANCE.getDevices(name, ACCOUNT.getIdAndDomain());
+ return OmemoDeviceDBManager.INSTANCE.getDevices(name, ACCOUNT.getBareJid());
}
public void StoreDeviceListSubscription(string name, Tuple lastUpdate)
{
- OmemoDeviceDBManager.INSTANCE.setOmemoDeviceListSubscription(name, lastUpdate, ACCOUNT.getIdAndDomain());
+ OmemoDeviceDBManager.INSTANCE.setOmemoDeviceListSubscription(name, lastUpdate, ACCOUNT.getBareJid());
}
public Tuple LoadDeviceListSubscription(string name)
{
- return OmemoDeviceDBManager.INSTANCE.getOmemoDeviceListSubscription(name, ACCOUNT.getIdAndDomain());
+ return OmemoDeviceDBManager.INSTANCE.getOmemoDeviceListSubscription(name, ACCOUNT.getBareJid());
}
#endregion
diff --git a/Data_Manager2/Classes/SettingsConsts.cs b/Data_Manager2/Classes/SettingsConsts.cs
index 8d5ccaad2..03c1af7a7 100644
--- a/Data_Manager2/Classes/SettingsConsts.cs
+++ b/Data_Manager2/Classes/SettingsConsts.cs
@@ -4,7 +4,7 @@ public static class SettingsConsts
{
public const string INITIALLY_STARTED = "initially_started";
public const string HIDE_INITIAL_START_DIALOG_ALPHA = "hide_initial_start_dialog_alpha";
- public const string HIDE_WHATS_NEW_DIALOG = "hide_whats_new_dialog_alpha_12";
+ public const string HIDE_WHATS_NEW_DIALOG = "hide_whats_new_dialog_alpha_14";
public const string APP_REQUESTED_THEME = "app_requested_theme";
@@ -18,10 +18,13 @@ public static class SettingsConsts
public const string DONT_SEND_CHAT_MESSAGE_RECEIVED_MARKERS = "dont_send_chat_message_received_markers";
public const string DISABLE_PUSH = "disable_push";
public const string DISABLE_DOWNLOAD_IMAGES_TO_LIBARY = "disable_download_images_to_libary";
+ public const string DISABLE_IMAGE_AUTO_DOWNLOAD = "disable_image_auto_download";
public const string DISABLE_CRASH_REPORTING = "disable_crash_reporting";
public const string DISABLE_ANALYTICS = "disable_analytics";
public const string DISABLE_AUTO_JOIN_MUC = "disable_auto_join_muc";
public const string DISABLE_ADVANCED_CHAT_MESSAGE_PROCESSING = "disable_advanced_chat_message_processing";
+ public const string ENABLE_OMEMO_BY_DEFAULT_FOR_NEW_CHATS = "enable_omemo_by_default_for_new_chats";
+ public const string DISABLE_VIBRATION_FOR_NEW_CHAT_MESSAGES = "disable_vibration_for_new_chat_messages";
public const string PUSH_CHANNEL_TOKEN_URL = "push_channel_token_url";
public const string PUSH_CHANNEL_SEND_SUCCESS = "push_channel_send_success";
@@ -31,13 +34,22 @@ public static class SettingsConsts
public const string VERSION_BUILD = "version_build";
public const string VERSION_REVISION = "version_revision";
public const string LOG_LEVEL = "log_level";
+ public const string DEBUG_SETTINGS_ENABLED = "debug_settings_enabled";
- public const string CHAT_FILTER_PRESENCES = "chat_filter_presences";
+ public const string CHAT_FILTER_PRESENCE_ONLINE = "chat_filter_presence_online";
+ public const string CHAT_FILTER_PRESENCE_AWAY = "chat_filter_presence_away";
+ public const string CHAT_FILTER_PRESENCE_UNAVAILABLE = "chat_filter_presence_unavailable";
+ public const string CHAT_FILTER_PRESENCE_DND = "chat_filter_presence_dnd";
+ public const string CHAT_FILTER_PRESENCE_XA = "chat_filter_presence_xa";
+ public const string CHAT_FILTER_PRESENCE_CHAT = "chat_filter_presence_chat";
public const string CHAT_FILTER_NOT_ONLINE = "chat_filter_not_online";
public const string CHAT_FILTER_NOT_UNAVAILABLE = "chat_filter_not_unavailable";
public const string CHAT_FILTER_QUERY = "chat_filter_query";
public const string CHAT_FILTER_QUERY_ENABLED = "chat_filter_query_enabled";
- public const string CHAT_FILTER_CHAT = "chat_filter_chat";
- public const string CHAT_FILTER_MUC = "chat_filter_muc";
+ public const string CHAT_FILTER_CHATS_ONLY = "chat_filter_chats_only";
+ public const string CHAT_FILTER_MUCS_ONLY = "chat_filter_mucs_only";
+ public const string SPAM_DETECTION_ENABLED = "spam_detection_enabled";
+ public const string SPAM_DETECTION_FOR_ALL_CHAT_MESSAGES = "spam_detection_for_all_chat_messages";
+ public const string SPAM_REGEX = "spam_regex";
}
}
diff --git a/Data_Manager2/Classes/Toast/ToastHelper.cs b/Data_Manager2/Classes/Toast/ToastHelper.cs
index 36dda6cd1..b01d79fc3 100644
--- a/Data_Manager2/Classes/Toast/ToastHelper.cs
+++ b/Data_Manager2/Classes/Toast/ToastHelper.cs
@@ -1,10 +1,10 @@
using Data_Manager2.Classes.DBTables;
using Logging;
using Microsoft.Toolkit.Uwp.Notifications;
-using Windows.UI.Notifications;
-using Windows.Phone.Devices.Notification;
using System;
using Windows.Foundation.Metadata;
+using Windows.Phone.Devices.Notification;
+using Windows.UI.Notifications;
namespace Data_Manager2.Classes.Toast
{
@@ -185,7 +185,7 @@ private static void popToast(ToastContent content, ChatTable chat)
private static void popToastReduced()
{
- if(ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice"))
+ if (ApiInformation.IsTypePresent("Windows.Phone.Devices.Notification.VibrationDevice") && !Settings.getSettingBoolean(SettingsConsts.DISABLE_VIBRATION_FOR_NEW_CHAT_MESSAGES))
{
VibrationDevice.GetDefault().Vibrate(VIBRATE_TS);
}
diff --git a/Data_Manager2/Classes/Vault.cs b/Data_Manager2/Classes/Vault.cs
index 9fdec8549..18f11b2cd 100644
--- a/Data_Manager2/Classes/Vault.cs
+++ b/Data_Manager2/Classes/Vault.cs
@@ -28,10 +28,10 @@ public static class Vault
/// The XMPPAccount you want to retrieve the PasswordCredential for.
private static PasswordCredential getPasswordCredentialForAccount(XMPPAccount account)
{
- string vaultName = VAULT_NAME_PREFIX + account.getIdAndDomain();
+ string vaultName = VAULT_NAME_PREFIX + account.getBareJid();
try
{
- return PASSWORD_VAULT.Retrieve(vaultName, account.user.userId);
+ return PASSWORD_VAULT.Retrieve(vaultName, account.user.localPart);
}
catch (Exception)
{
@@ -69,12 +69,12 @@ public static void loadPassword(XMPPAccount account)
PasswordCredential passwordCredential = getPasswordCredentialForAccount(account);
if (passwordCredential is null)
{
- Logger.Warn("No password found for: " + account.user.getIdAndDomain());
- account.user.userPassword = "";
+ Logger.Warn("No password found for: " + account.user.getBareJid());
+ account.user.password = "";
return;
}
passwordCredential.RetrievePassword();
- account.user.userPassword = passwordCredential.Password;
+ account.user.password = passwordCredential.Password;
}
///
@@ -89,10 +89,10 @@ public static void storePassword(XMPPAccount account)
//removeAll();
// Store the new password:
- if(!string.IsNullOrEmpty(account.user.userPassword))
+ if (!string.IsNullOrEmpty(account.user.password))
{
- string vaultName = VAULT_NAME_PREFIX + account.getIdAndDomain();
- PASSWORD_VAULT.Add(new PasswordCredential(vaultName, account.user.userId, account.user.userPassword));
+ string vaultName = VAULT_NAME_PREFIX + account.getBareJid();
+ PASSWORD_VAULT.Add(new PasswordCredential(vaultName, account.user.localPart, account.user.password));
}
}
diff --git a/Data_Manager2/Data_Manager2.csproj b/Data_Manager2/Data_Manager2.csproj
index 080694272..54430dfcf 100644
--- a/Data_Manager2/Data_Manager2.csproj
+++ b/Data_Manager2/Data_Manager2.csproj
@@ -4,15 +4,15 @@
Debug
AnyCPU
- {CB58CE53-8E53-49C8-9936-15FE2EA6A7EB}
+ {58925BF1-5B7D-48D9-B411-126CBEFDA98A}
Library
Properties
Data_Manager2
Data_Manager2
- de-DE
+ en-US
UAP
- 10.0.16299.0
- 10.0.10586.0
+ 10.0.17763.0
+ 10.0.15063.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -26,6 +26,7 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
AnyCPU
@@ -35,6 +36,7 @@
TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
x86
@@ -43,9 +45,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x86
false
prompt
+ latest
x86
@@ -54,9 +56,9 @@
true
;2008
pdbonly
- x86
false
prompt
+ latest
ARM
@@ -65,9 +67,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- ARM
false
prompt
+ latest
ARM
@@ -76,9 +78,31 @@
true
;2008
pdbonly
- ARM
false
prompt
+ latest
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+ latest
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+ latest
x64
@@ -87,9 +111,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x64
false
prompt
+ latest
x64
@@ -98,15 +122,14 @@
true
;2008
pdbonly
- x64
false
prompt
+ latest
PackageReference
-
@@ -116,40 +139,41 @@
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
@@ -162,40 +186,36 @@
-
- 6.2.2
+ 6.2.3
4.0.0
-
- 4.0.0
-
-
-
-
- Windows Mobile Extensions for the UWP
-
- {53bb5463-9646-4f79-be97-3d73473aad92}
+ {0c1fb090-4492-441d-b182-c999df71f917}
Logging
-
- {60938c69-a2d7-4c27-8b73-84c203bd4787}
- Thread_Save_Components
+
+ {c4af94da-11cf-4147-b5b7-4b2dc7c624a0}
+ Shared
- {899fb043-af8b-4294-95b6-1482c79459ac}
+ {64b9a47f-d404-4d0b-a34a-bec280c5ff6b}
XMPP_API
+
+
+ Windows Mobile Extensions for the UWP
+
+
14.0
diff --git a/Data_Manager2/Properties/AssemblyInfo.cs b/Data_Manager2/Properties/AssemblyInfo.cs
index 297dd12e2..1e77633c6 100644
--- a/Data_Manager2/Properties/AssemblyInfo.cs
+++ b/Data_Manager2/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Data_Manager2")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/Data_Manager2/Properties/Data_Manager2.rd.xml b/Data_Manager2/Properties/Data_Manager2.rd.xml
index 7a208c2d5..bf9a4cbf3 100644
--- a/Data_Manager2/Properties/Data_Manager2.rd.xml
+++ b/Data_Manager2/Properties/Data_Manager2.rd.xml
@@ -1,33 +1,33 @@
-
+
diff --git a/Logging/Logger.cs b/Logging/Logger.cs
index c0ceac295..fb0d74cc4 100644
--- a/Logging/Logger.cs
+++ b/Logging/Logger.cs
@@ -70,7 +70,7 @@ public static async Task getLogFolderSizeAsync()
/// Returns the "Logs" folder and creates it, if it does not exist.
///
/// Returns the "Logs" folder.
- private static async Task getLogFolderAsync()
+ public static async Task getLogFolderAsync()
{
return await ApplicationData.Current.LocalFolder.CreateFolderAsync("Logs", CreationCollisionOption.OpenIfExists);
}
@@ -204,7 +204,7 @@ public static async Task deleteLogsAsync()
///
/// Exports all logs as a .zip file to the selected path.
///
- public static async Task exportLogs()
+ public static async Task exportLogsAsync()
{
// Get the target path/file.
StorageFile targetFile = await getTargetPathAsync().ConfigureAwait(false);
diff --git a/Logging/Logging.csproj b/Logging/Logging.csproj
index c466bef41..a35b3e79c 100644
--- a/Logging/Logging.csproj
+++ b/Logging/Logging.csproj
@@ -4,15 +4,15 @@
Debug
AnyCPU
- {53BB5463-9646-4F79-BE97-3D73473AAD92}
+ {0C1FB090-4492-441D-B182-C999DF71F917}
Library
Properties
Logging
Logging
- de-DE
+ en-US
UAP
- 10.0.16299.0
- 10.0.10586.0
+ 10.0.17763.0
+ 10.0.15063.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -26,6 +26,7 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
AnyCPU
@@ -35,6 +36,7 @@
TRACE;NETFX_CORE;WINDOWS_UWP
prompt
4
+ latest
x86
@@ -43,9 +45,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x86
false
prompt
+ latest
x86
@@ -54,9 +56,9 @@
true
;2008
pdbonly
- x86
false
prompt
+ latest
ARM
@@ -65,9 +67,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- ARM
false
prompt
+ latest
ARM
@@ -76,9 +78,31 @@
true
;2008
pdbonly
- ARM
false
prompt
+ latest
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+ latest
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+ latest
x64
@@ -87,9 +111,9 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x64
false
prompt
+ latest
x64
@@ -98,25 +122,24 @@
true
;2008
pdbonly
- x64
false
prompt
+ latest
PackageReference
-
-
+
- 6.2.2
+ 6.2.3
4.5.11
diff --git a/Logging/Properties/AssemblyInfo.cs b/Logging/Properties/AssemblyInfo.cs
index eb56bee48..23adf979a 100644
--- a/Logging/Properties/AssemblyInfo.cs
+++ b/Logging/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Logging")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/Logging/Properties/Logging.rd.xml b/Logging/Properties/Logging.rd.xml
index 0de744a6d..f3b106ce5 100644
--- a/Logging/Properties/Logging.rd.xml
+++ b/Logging/Properties/Logging.rd.xml
@@ -1,33 +1,33 @@
-
+
diff --git a/Push_App_Server/Classes/DataWriter.cs b/Push_App_Server/Classes/DataWriter.cs
index 7f571bd7e..c2dd7ec5e 100644
--- a/Push_App_Server/Classes/DataWriter.cs
+++ b/Push_App_Server/Classes/DataWriter.cs
@@ -37,22 +37,22 @@ public DataWriter(XMPPClient client)
#region --Set-, Get- Methods--
private bool getChannelSuccess()
{
- return Settings.getSettingBoolean(SettingsConsts.PUSH_CHANNEL_SEND_SUCCESS + client.getXMPPAccount().getIdAndDomain());
+ return Settings.getSettingBoolean(SettingsConsts.PUSH_CHANNEL_SEND_SUCCESS + client.getXMPPAccount().getBareJid());
}
private void setChannelSuccess(bool success)
{
- Settings.setSetting(SettingsConsts.PUSH_CHANNEL_SEND_SUCCESS + client.getXMPPAccount().getIdAndDomain(), success);
+ Settings.setSetting(SettingsConsts.PUSH_CHANNEL_SEND_SUCCESS + client.getXMPPAccount().getBareJid(), success);
}
private string getOldChannelTokenUrl()
{
- return Settings.getSettingString(SettingsConsts.PUSH_CHANNEL_TOKEN_URL + client.getXMPPAccount().getIdAndDomain());
+ return Settings.getSettingString(SettingsConsts.PUSH_CHANNEL_TOKEN_URL + client.getXMPPAccount().getBareJid());
}
private void setChannelTokenUrl(string url)
{
- Settings.setSetting(SettingsConsts.PUSH_CHANNEL_TOKEN_URL + client.getXMPPAccount().getIdAndDomain(), url);
+ Settings.setSetting(SettingsConsts.PUSH_CHANNEL_TOKEN_URL + client.getXMPPAccount().getBareJid(), url);
}
#endregion
@@ -162,7 +162,7 @@ public async Task requestChannelAsync()
private string getMessage(string url)
{
XElement n = new XElement("push");
- n.Add(new XAttribute("clientId", client.getXMPPAccount().getIdAndDomain()));
+ n.Add(new XAttribute("clientId", client.getXMPPAccount().getBareJid()));
n.Add(new XAttribute("pushChannel", url));
return n.ToString();
}
diff --git a/Push_App_Server/Classes/PushConnection.cs b/Push_App_Server/Classes/PushConnection.cs
index c4b03fae1..1277878d7 100644
--- a/Push_App_Server/Classes/PushConnection.cs
+++ b/Push_App_Server/Classes/PushConnection.cs
@@ -20,7 +20,11 @@ public class PushConnection : AbstractConnection2
///
/// A dummy XMPPAccount its only purpose it is to allow using the TCPConnection.
///
- private static readonly XMPPAccount DUMMY_XMPP_ACCOUNT = new XMPPAccount(null, Consts.PUSH_SERVER_ADDRESS, Consts.PORT);
+ private static readonly XMPPAccount DUMMY_XMPP_ACCOUNT = new XMPPAccount(null)
+ {
+ serverAddress = Consts.PUSH_SERVER_ADDRESS,
+ port = Consts.PORT
+ };
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
diff --git a/Push_App_Server/Properties/AssemblyInfo.cs b/Push_App_Server/Properties/AssemblyInfo.cs
index a88f59260..f728f3d10 100644
--- a/Push_App_Server/Properties/AssemblyInfo.cs
+++ b/Push_App_Server/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Push_App_Server")]
-[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/Push_App_Server/Properties/Push_App_Server.rd.xml b/Push_App_Server/Properties/Push_App_Server.rd.xml
index 97e98d529..b2652f1a5 100644
--- a/Push_App_Server/Properties/Push_App_Server.rd.xml
+++ b/Push_App_Server/Properties/Push_App_Server.rd.xml
@@ -1,33 +1,33 @@
-
+
diff --git a/Push_App_Server/Push_App_Server.csproj b/Push_App_Server/Push_App_Server.csproj
index f36ff7bda..c4189c33d 100644
--- a/Push_App_Server/Push_App_Server.csproj
+++ b/Push_App_Server/Push_App_Server.csproj
@@ -4,15 +4,15 @@
Debug
AnyCPU
- {A8DA7BD0-DC43-4F30-AB1E-3FCF942274E4}
+ {C8F34602-1D87-428C-836A-E4295C4C15D8}
Library
Properties
Push_App_Server
Push_App_Server
- de-DE
+ en-US
UAP
- 10.0.16299.0
- 10.0.10586.0
+ 10.0.17763.0
+ 10.0.15063.0
14
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -43,7 +43,6 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x86
false
prompt
@@ -54,7 +53,6 @@
true
;2008
pdbonly
- x86
false
prompt
@@ -65,7 +63,6 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- ARM
false
prompt
@@ -76,7 +73,26 @@
true
;2008
pdbonly
- ARM
+ false
+ prompt
+
+
+ ARM64
+ true
+ bin\ARM64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM64
+ bin\ARM64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
false
prompt
@@ -87,7 +103,6 @@
DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
;2008
full
- x64
false
prompt
@@ -98,7 +113,6 @@
true
;2008
pdbonly
- x64
false
prompt
@@ -106,7 +120,6 @@
PackageReference
-
@@ -116,20 +129,24 @@
- 6.2.2
+ 6.2.3
- {cb58ce53-8e53-49c8-9936-15fe2ea6a7eb}
+ {58925bf1-5b7d-48d9-b411-126cbefda98a}
Data_Manager2
- {53bb5463-9646-4f79-be97-3d73473aad92}
+ {0c1fb090-4492-441d-b182-c999df71f917}
Logging
+
+ {c4af94da-11cf-4147-b5b7-4b2dc7c624a0}
+ Shared
+
- {899fb043-af8b-4294-95b6-1482c79459ac}
+ {64b9a47f-d404-4d0b-a34a-bec280c5ff6b}
XMPP_API
diff --git a/README.md b/README.md
index 98125c3b9..f25dcc12e 100644
--- a/README.md
+++ b/README.md
@@ -73,10 +73,11 @@ An alpha version of the app is available in the Windows Store [LINK](https://www
[Here](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) you can find more information about: How to install UWP apps, using the developer mode.
## Examples:
-
-
-
-
+
+
+
+
+
## References:
This project wouldn’t be possible without the great work of all those people working on the libraries used by UWPX.
diff --git a/Shared/Classes/AbstractDataTemplate.cs b/Shared/Classes/AbstractDataTemplate.cs
new file mode 100644
index 000000000..3c087701f
--- /dev/null
+++ b/Shared/Classes/AbstractDataTemplate.cs
@@ -0,0 +1,75 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace Shared.Classes
+{
+ ///
+ /// Based on: https://github.com/Microsoft/Windows-appsample-trafficapp/blob/master/LocationHelper/BindableBase.cs
+ ///
+ public abstract class AbstractDataTemplate : INotifyPropertyChanged
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ public event PropertyChangedEventHandler PropertyChanged;
+ ///
+ /// Decides whether the property changed event should be fired in the UI thread.
+ /// Default: true
+ ///
+ protected bool invokeInUiThread = true;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+ protected bool SetProperty(ref T storage, T value, [CallerMemberName] string propertyName = null)
+ {
+ if (Equals(storage, value))
+ {
+ return false;
+ }
+
+ storage = value;
+ OnPropertyChanged(propertyName);
+ return true;
+ }
+
+ protected virtual async void OnPropertyChanged([CallerMemberName] string name = "")
+ {
+ if (invokeInUiThread)
+ {
+ // Make sure we call the PropertyChanged event from the UI thread:
+ await SharedUtils.CallDispatcherAsync(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)));
+ }
+ else
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
+ }
+ }
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Shared/Classes/Collections/CustomObservableCollection.cs b/Shared/Classes/Collections/CustomObservableCollection.cs
new file mode 100644
index 000000000..8491af089
--- /dev/null
+++ b/Shared/Classes/Collections/CustomObservableCollection.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Linq;
+
+namespace Shared.Classes.Collections
+{
+ ///
+ /// Based on: https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each/45364074#45364074
+ ///
+ public class CustomObservableCollection : ObservableCollection
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ private const string CountName = nameof(Count);
+ private const string IndexerName = "Item[]";
+ public readonly bool INVOKE_IN_UI_THREAD;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+ public CustomObservableCollection(bool invokeInUiThread) : base()
+ {
+ this.INVOKE_IN_UI_THREAD = invokeInUiThread;
+ }
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ ///
+ /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
+ ///
+ public void AddRange(IEnumerable collection)
+ {
+ if (collection is null)
+ {
+ throw new ArgumentNullException(nameof(collection));
+ }
+
+ if (collection is ICollection list)
+ {
+ if (list.Count == 0) return;
+ }
+ else if (!collection.Any())
+ {
+ return;
+ }
+ else
+ {
+ list = new List(collection);
+ }
+
+ CheckReentrancy();
+
+ int startIndex = Count;
+ foreach (var i in collection)
+ {
+ Items.Add(i);
+ }
+
+ NotifyProperties();
+ OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list is IList ? list : list.ToList(), startIndex));
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+ private void NotifyProperties(bool count = true)
+ {
+ if (count)
+ {
+ OnPropertyChanged(new PropertyChangedEventArgs(CountName));
+ }
+ OnPropertyChanged(new PropertyChangedEventArgs(IndexerName));
+ }
+
+ private void OnCollectionReset() => OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+ protected override void RemoveItem(int index)
+ {
+ if (Items[index] is INotifyPropertyChanged i)
+ {
+ i.PropertyChanged -= CustomObservableCollection_PropertyChanged;
+ }
+ base.RemoveItem(index);
+ }
+
+ protected override void InsertItem(int index, T item)
+ {
+ if (item is INotifyPropertyChanged i)
+ {
+ i.PropertyChanged += CustomObservableCollection_PropertyChanged;
+ }
+ base.InsertItem(index, item);
+ }
+
+ protected override void SetItem(int index, T item)
+ {
+ if (Items[index] is INotifyPropertyChanged i)
+ {
+ i.PropertyChanged -= CustomObservableCollection_PropertyChanged;
+ }
+ if (item is INotifyPropertyChanged iNew)
+ {
+ iNew.PropertyChanged += CustomObservableCollection_PropertyChanged;
+ }
+ (item as INotifyPropertyChanged).PropertyChanged += CustomObservableCollection_PropertyChanged;
+ base.SetItem(index, item);
+ }
+
+ protected async override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
+ {
+ if (INVOKE_IN_UI_THREAD)
+ {
+ await SharedUtils.CallDispatcherAsync(() => base.OnCollectionChanged(e));
+ }
+ else
+ {
+ base.OnCollectionChanged(e);
+ }
+ }
+
+ protected async override void OnPropertyChanged(PropertyChangedEventArgs e)
+ {
+ if (INVOKE_IN_UI_THREAD)
+ {
+ await SharedUtils.CallDispatcherAsync(() => base.OnPropertyChanged(e));
+ }
+ else
+ {
+ base.OnPropertyChanged(e);
+ }
+ }
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+ private void CustomObservableCollection_PropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ OnPropertyChanged(e);
+ }
+
+ #endregion
+ }
+}
diff --git a/Thread_Save_Components/Classes/Collections/ITimedEntry.cs b/Shared/Classes/Collections/ITimedEntry.cs
similarity index 58%
rename from Thread_Save_Components/Classes/Collections/ITimedEntry.cs
rename to Shared/Classes/Collections/ITimedEntry.cs
index 5998fc1c9..156e73fff 100644
--- a/Thread_Save_Components/Classes/Collections/ITimedEntry.cs
+++ b/Shared/Classes/Collections/ITimedEntry.cs
@@ -1,4 +1,4 @@
-namespace Thread_Save_Components.Classes.Collections
+namespace Shared.Classes.Collections
{
public interface ITimedEntry
{
diff --git a/Thread_Save_Components/Classes/Collections/TSTimedList.cs b/Shared/Classes/Collections/TSTimedList.cs
similarity index 98%
rename from Thread_Save_Components/Classes/Collections/TSTimedList.cs
rename to Shared/Classes/Collections/TSTimedList.cs
index 6408c1a94..2b17006b3 100644
--- a/Thread_Save_Components/Classes/Collections/TSTimedList.cs
+++ b/Shared/Classes/Collections/TSTimedList.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading;
-namespace Thread_Save_Components.Classes.Collections
+namespace Shared.Classes.Collections
{
public class TSTimedList
{
diff --git a/Thread_Save_Components/Classes/Collections/TimedListEntry.cs b/Shared/Classes/Collections/TimedListEntry.cs
similarity index 95%
rename from Thread_Save_Components/Classes/Collections/TimedListEntry.cs
rename to Shared/Classes/Collections/TimedListEntry.cs
index 138e54a0f..1b055fe41 100644
--- a/Thread_Save_Components/Classes/Collections/TimedListEntry.cs
+++ b/Shared/Classes/Collections/TimedListEntry.cs
@@ -1,6 +1,6 @@
using System;
-namespace Thread_Save_Components.Classes.Collections
+namespace Shared.Classes.Collections
{
public class TimedListEntry : ITimedEntry
{
@@ -34,7 +34,7 @@ public TimedListEntry(T item)
#region --Misc Methods (Public)--
public bool canGetRemoved()
{
- if(item is ITimedEntry)
+ if (item is ITimedEntry)
{
return (item as ITimedEntry).canGetRemoved();
}
diff --git a/Shared/Classes/Network/AbstractDownloadableObject.cs b/Shared/Classes/Network/AbstractDownloadableObject.cs
new file mode 100644
index 000000000..c63bb0df9
--- /dev/null
+++ b/Shared/Classes/Network/AbstractDownloadableObject.cs
@@ -0,0 +1,96 @@
+namespace Shared.Classes.Network
+{
+ public abstract class AbstractDownloadableObject : AbstractDataTemplate
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ protected DownloadState _State;
+ ///
+ /// The current state of the download.
+ ///
+ public DownloadState State
+ {
+ get { return _State; }
+ set { SetProperty(ref _State, value); }
+ }
+ protected double _Progress;
+ ///
+ /// The download progress in percent.
+ ///
+ public double Progress
+ {
+ get { return _Progress; }
+ set { SetProperty(ref _Progress, value); }
+ }
+ protected string _SourceUrl;
+ ///
+ /// The url where the object should get downloaded from.
+ ///
+ public string SourceUrl
+ {
+ get { return _SourceUrl; }
+ set { SetProperty(ref _SourceUrl, value); }
+ }
+ protected string _TargetFolderPath;
+ ///
+ /// The target folder path, where the downloaded object should get saved to.
+ /// E.g.: C:\Program Files\Git
+ ///
+ public string TargetFolderPath
+ {
+ get { return _TargetFolderPath; }
+ set { SetProperty(ref _TargetFolderPath, value); }
+ }
+ protected string _TargetFileName;
+ ///
+ /// The name of the downloaded object with extension.
+ /// E.g.: file.png
+ ///
+ public string TargetFileName
+ {
+ get { return _TargetFileName; }
+ set { SetProperty(ref _TargetFileName, value); }
+ }
+ protected DownloadError _Error;
+ ///
+ /// The error code if one occurred.
+ ///
+ public DownloadError Error
+ {
+ get { return _Error; }
+ set { SetProperty(ref _Error, value); }
+ }
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Shared/Classes/Network/DownloadError.cs b/Shared/Classes/Network/DownloadError.cs
new file mode 100644
index 000000000..9cffed060
--- /dev/null
+++ b/Shared/Classes/Network/DownloadError.cs
@@ -0,0 +1,8 @@
+namespace Shared.Classes.Network
+{
+ public enum DownloadError
+ {
+ FAILED_TO_CREATE_LOCAL_PATH,
+ INVALID_STATUS_CODE
+ }
+}
diff --git a/Shared/Classes/Network/DownloadHandler.cs b/Shared/Classes/Network/DownloadHandler.cs
new file mode 100644
index 000000000..a1e5634e5
--- /dev/null
+++ b/Shared/Classes/Network/DownloadHandler.cs
@@ -0,0 +1,306 @@
+using Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.Storage;
+
+namespace Shared.Classes.Network
+{
+ public class DownloadHandler : IDisposable
+ {
+ //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
+ #region --Attributes--
+ public const int MAX_CONCURRENT_DOWNLOADS = 2;
+ private readonly Task[] DOWNLOADER = new Task[MAX_CONCURRENT_DOWNLOADS];
+ private readonly CancellationTokenSource[] DOWNLOADER_CANCELLATION_TOKENS = new CancellationTokenSource[MAX_CONCURRENT_DOWNLOADS];
+
+ private readonly List TO_DOWNLOAD = new List();
+ private readonly List DOWNLOADING = new List();
+ private readonly SemaphoreSlim DOWNLOADING_SEMA = new SemaphoreSlim(1);
+ private readonly SemaphoreSlim TO_DOWNLOAD_SEMA = new SemaphoreSlim(1);
+ private readonly SemaphoreSlim TO_DOWNLOAD_COUNT_SEMA = new SemaphoreSlim(0);
+
+ public delegate void DownloadStateChangedHandler(AbstractDownloadableObject o, DownloadStateChangedEventArgs args);
+
+ public event DownloadStateChangedHandler DownloadStateChanged;
+
+ #endregion
+ //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
+ #region --Constructors--
+ public DownloadHandler()
+ {
+ StartDownloaderTasks();
+ }
+
+ #endregion
+ //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
+ #region --Set-, Get- Methods--
+ public async Task FindAsync(Predicate predicate)
+ {
+ AbstractDownloadableObject result = null;
+ await TO_DOWNLOAD_SEMA.WaitAsync();
+ result = TO_DOWNLOAD.Find(predicate);
+ TO_DOWNLOAD_SEMA.Release();
+ if (!(result is null))
+ {
+ return result;
+ }
+
+ DOWNLOADING_SEMA.Wait();
+ result = DOWNLOADING.Find(predicate);
+ DOWNLOADING_SEMA.Release();
+ if (!(result is null))
+ {
+ return result;
+ }
+ return null;
+ }
+
+ private void SetDownloadState(AbstractDownloadableObject o, DownloadState newState)
+ {
+ if (o.State != newState)
+ {
+ DownloadStateChangedEventArgs args = new DownloadStateChangedEventArgs(o.State, newState);
+ o.State = newState;
+ DownloadStateChanged?.Invoke(o, args);
+ }
+ }
+
+ #endregion
+ //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
+ #region --Misc Methods (Public)--
+ public async Task EnqueueDownloadAsync(AbstractDownloadableObject o)
+ {
+ SetDownloadState(o, DownloadState.QUEUED);
+ await TO_DOWNLOAD_SEMA.WaitAsync();
+ TO_DOWNLOAD.Add(o);
+ TO_DOWNLOAD_SEMA.Release();
+ TO_DOWNLOAD_COUNT_SEMA.Release();
+ }
+
+ public void CancelDownload(AbstractDownloadableObject o)
+ {
+ SetDownloadState(o, DownloadState.CANCELED);
+ }
+
+ #endregion
+
+ #region --Misc Methods (Private)--
+ private void StartDownloaderTasks()
+ {
+ for (int i = 0; i < DOWNLOADER.Length; i++)
+ {
+ DOWNLOADER_CANCELLATION_TOKENS[i] = new CancellationTokenSource();
+ DOWNLOADER[i] = StartDownlaoderTask(i);
+ }
+ }
+
+ ///
+ /// Starts a new downloader Task and returns it.
+ ///
+ /// The index of the downloader Task.
+ /// Returns a new downloader Task.
+ private Task StartDownlaoderTask(int index)
+ {
+ return Task.Run(async () =>
+ {
+ while (!DOWNLOADER_CANCELLATION_TOKENS[index].IsCancellationRequested)
+ {
+ try
+ {
+ // Wait until downloads are available:
+ await TO_DOWNLOAD_COUNT_SEMA.WaitAsync();
+ Logger.Debug("Downloader task " + index + " started job.");
+
+ // Remove one download:
+ await TO_DOWNLOAD_SEMA.WaitAsync();
+ AbstractDownloadableObject o = TO_DOWNLOAD[0];
+ TO_DOWNLOAD.RemoveAt(0);
+ TO_DOWNLOAD_SEMA.Release();
+
+ if (o.State != DownloadState.CANCELED)
+ {
+ SetDownloadState(o, DownloadState.DOWNLOADING);
+ o.Progress = 0;
+
+ // Add to currently downloading:
+ await DOWNLOADING_SEMA.WaitAsync();
+ DOWNLOADING.Add(o);
+ DOWNLOADING_SEMA.Release();
+
+ // Download:
+ await DownloadAsync(o);
+
+ // Remove since the download finished:
+ await DOWNLOADING_SEMA.WaitAsync();
+ DOWNLOADING.Remove(o);
+ DOWNLOADING_SEMA.Release();
+ }
+ Logger.Debug("Downloader task " + index + " finished job.");
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Downloader task " + index + " job failed with: ", e);
+ }
+ }
+
+ }, DOWNLOADER_CANCELLATION_TOKENS[index].Token);
+ }
+
+ private void CancelDownloaderTasks()
+ {
+ for (int i = 0; i < DOWNLOADER.Length; i++)
+ {
+ if (!(DOWNLOADER[i] is null))
+ {
+ DOWNLOADER_CANCELLATION_TOKENS[i].Cancel();
+ DOWNLOADER[i] = null;
+ }
+ }
+ }
+
+ private async Task DownloadAsync(AbstractDownloadableObject o)
+ {
+ Logger.Info("Started downloading <" + o.TargetFileName + "> from: " + o.SourceUrl);
+ HttpWebRequest request = (HttpWebRequest)WebRequest.Create(o.SourceUrl);
+ HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
+ long bytesReadTotal = 0;
+
+ // Check that the remote file was found.
+ // The ContentType check is performed since a request for a non-existent image file might be redirected to a 404-page, which would yield the StatusCode "OK", even though the image was not found.
+ if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.Redirect)
+ {
+ StorageFile file = await GenFilePathAsync(o.TargetFolderPath, o.TargetFileName);
+ if (file is null)
+ {
+ o.Error = DownloadError.FAILED_TO_CREATE_LOCAL_PATH;
+ SetDownloadState(o, DownloadState.ERROR);
+ return;
+ }
+
+ using (Stream inputStream = response.GetResponseStream())
+ using (Stream outputStream = await file.OpenStreamForWriteAsync())
+ {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ do
+ {
+ bytesRead = await inputStream.ReadAsync(buffer, 0, buffer.Length);
+ await outputStream.WriteAsync(buffer, 0, bytesRead);
+
+ // Update progress:
+ bytesReadTotal += bytesRead;
+ UpdateDownloadProgress(o, response.ContentLength, bytesReadTotal);
+
+ } while (bytesRead != 0 && o.State != DownloadState.CANCELED);
+ }
+
+ if (o.State == DownloadState.CANCELED)
+ {
+ Logger.Info("Canceled downloading <" + o.TargetFileName + "> from: " + o.SourceUrl);
+ return;
+ }
+
+ SetDownloadState(o, DownloadState.DONE);
+ Logger.Info("Finished downloading <" + o.TargetFileName + "> from: " + o.SourceUrl);
+ }
+ else
+ {
+ o.Error = DownloadError.INVALID_STATUS_CODE;
+ SetDownloadState(o, DownloadState.ERROR);
+ Logger.Error("Unable to download image <" + o.TargetFileName + "> from: " + o.SourceUrl + "- Status code check failed: " + response.StatusCode + "(" + response.StatusDescription + ')');
+ }
+ }
+
+ private async Task GenFilePathAsync(string folderPath, string fileName)
+ {
+ //CreateDirectoryRecursively(folderPath);
+ StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(folderPath);
+ if (!(folder is null))
+ {
+ return await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
+ }
+ Logger.Error("Failed to get folder from path: " + folderPath);
+ return null;
+ }
+
+ ///
+ /// Creates all directories for the given path recursively.
+ /// Based on: https://stackoverflow.com/questions/10941657/creating-files-recursively-creating-directories
+ ///
+ /// The absolute directory path.
+ private void CreateDirectoryRecursively(string path)
+ {
+ string[] pathParts = path.Split('\\');
+
+ for (int i = 0; i < pathParts.Length; i++)
+ {
+ if (i > 0)
+ {
+ pathParts[i] = Path.Combine(pathParts[i - 1], pathParts[i]);
+ }
+
+ if (!Directory.Exists(pathParts[i]))
+ {
+ Directory.CreateDirectory(pathParts[i]);
+ Logger.Debug("Created directory: " + pathParts[i]);
+ }
+ }
+ }
+
+ ///
+ /// Calculates the new download progress and sets it for the given AbstractDownloadableObject.
+ ///
+ /// The AbstractDownloadableObject.
+ /// The total size of the download in bytes.
+ /// How many bytes have been downloaded?
+ /// Returns the last progress update percentage.
+ private double UpdateDownloadProgress(AbstractDownloadableObject o, long totalSize, long bytesDownloadedTotal)
+ {
+ o.Progress = bytesDownloadedTotal / ((double)totalSize);
+ return o.Progress;
+ }
+
+ public void Dispose()
+ {
+ // Cancel all downloader tasks:
+ CancelDownloaderTasks();
+
+ // Clear download queue:
+ TO_DOWNLOAD_SEMA.Wait();
+ foreach (AbstractDownloadableObject o in TO_DOWNLOAD)
+ {
+ SetDownloadState(o, DownloadState.NOT_QUEUED);
+ }
+ TO_DOWNLOAD.Clear();
+ TO_DOWNLOAD_SEMA.Release();
+
+ // Stop all downloads:
+ DOWNLOADING_SEMA.Wait();
+ foreach (AbstractDownloadableObject o in DOWNLOADING)
+ {
+ if (o.State != DownloadState.DONE && o.State != DownloadState.ERROR)
+ {
+ SetDownloadState(o, DownloadState.NOT_QUEUED);
+ }
+ }
+ DOWNLOADING.Clear();
+ DOWNLOADING_SEMA.Release();
+ }
+
+ #endregion
+
+ #region --Misc Methods (Protected)--
+
+
+ #endregion
+ //--------------------------------------------------------Events:---------------------------------------------------------------------\\
+ #region --Events--
+
+
+ #endregion
+ }
+}
diff --git a/Shared/Classes/Network/DownloadState.cs b/Shared/Classes/Network/DownloadState.cs
new file mode 100644
index 000000000..56fc8e4bd
--- /dev/null
+++ b/Shared/Classes/Network/DownloadState.cs
@@ -0,0 +1,30 @@
+namespace Shared.Classes.Network
+{
+ public enum DownloadState
+ {
+ ///
+ /// The object is not in the download queue.
+ ///
+ NOT_QUEUED,
+ ///
+ /// The object is in the download queue and ready to be downloaded.
+ ///
+ QUEUED,
+ ///
+ /// The object is being downloaded.
+ ///
+ DOWNLOADING,
+ ///
+ /// The download finished without any errors.
+ ///
+ DONE,
+ ///
+ /// The download ended with an error.
+ ///
+ ERROR,
+ ///
+ /// The download has been canceled.
+ ///
+ CANCELED,
+ }
+}
diff --git a/Data_Manager2/Classes/Events/DownloadStateChangedEventArgs.cs b/Shared/Classes/Network/DownloadStateChangedEventArgs.cs
similarity index 75%
rename from Data_Manager2/Classes/Events/DownloadStateChangedEventArgs.cs
rename to Shared/Classes/Network/DownloadStateChangedEventArgs.cs
index db892274d..e45994e65 100644
--- a/Data_Manager2/Classes/Events/DownloadStateChangedEventArgs.cs
+++ b/Shared/Classes/Network/DownloadStateChangedEventArgs.cs
@@ -1,26 +1,21 @@
-using Data_Manager2.Classes;
-using System;
+using System;
-namespace Data_Manager2.Classes.Events
+namespace Shared.Classes.Network
{
public class DownloadStateChangedEventArgs : EventArgs
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
- public readonly DownloadState STATE;
+ public readonly DownloadState OLD_STATE;
+ public readonly DownloadState NEW_STATE;
#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
- ///
- /// Basic Constructor
- ///
- ///
- /// 18/12/2017 Created [Fabian Sauter]
- ///
- public DownloadStateChangedEventArgs(DownloadState state)
+ public DownloadStateChangedEventArgs(DownloadState oldState, DownloadState newState)
{
- this.STATE = state;
+ this.OLD_STATE = oldState;
+ this.NEW_STATE = newState;
}
#endregion
diff --git a/Thread_Save_Components/Classes/SQLite/AbstractDBManager.cs b/Shared/Classes/SQLite/AbstractDBManager.cs
similarity index 86%
rename from Thread_Save_Components/Classes/SQLite/AbstractDBManager.cs
rename to Shared/Classes/SQLite/AbstractDBManager.cs
index 466675356..0c82cb6f1 100644
--- a/Thread_Save_Components/Classes/SQLite/AbstractDBManager.cs
+++ b/Shared/Classes/SQLite/AbstractDBManager.cs
@@ -3,7 +3,7 @@
using System.IO;
using Windows.Storage;
-namespace Thread_Save_Components.Classes.SQLite
+namespace Shared.Classes.SQLite
{
public abstract class AbstractDBManager
{
@@ -82,21 +82,6 @@ protected void deleteDB()
///
protected abstract void createTables();
- ///
- /// Inserts or replaces the given object into the db.
- ///
- protected virtual void update(object obj)
- {
- try
- {
- dB.InsertOrReplace(obj);
- }
- catch (Exception e)
- {
- Logger.Error("Error in update", e);
- }
- }
-
#endregion
//--------------------------------------------------------Events:---------------------------------------------------------------------\\
#region --Events--
diff --git a/Thread_Save_Components/Classes/SQLite/TSSQLiteConnection.cs b/Shared/Classes/SQLite/TSSQLiteConnection.cs
similarity index 57%
rename from Thread_Save_Components/Classes/SQLite/TSSQLiteConnection.cs
rename to Shared/Classes/SQLite/TSSQLiteConnection.cs
index 3a6660029..0887b5b95 100644
--- a/Thread_Save_Components/Classes/SQLite/TSSQLiteConnection.cs
+++ b/Shared/Classes/SQLite/TSSQLiteConnection.cs
@@ -1,9 +1,10 @@
-using SQLite;
+using Logging;
+using SQLite;
using System;
using System.Collections.Generic;
using System.Threading;
-namespace Thread_Save_Components.Classes.SQLite
+namespace Shared.Classes.SQLite
{
public class TSSQLiteConnection : IDisposable
{
@@ -49,7 +50,7 @@ public TSSQLiteConnection(string dBPath)
#region --Misc Methods (Public)--
public SQLiteCommand CreateCommand(string cmdText, params object[] args)
{
- return DB_CONNECTIONS[DB_PATH].Item3.CreateCommand(cmdText, args);
+ return SharedUtils.RetryOnException(() => DB_CONNECTIONS[DB_PATH].Item3.CreateCommand(cmdText, args));
}
public void BeginTransaction()
@@ -58,7 +59,7 @@ public void BeginTransaction()
connection.Item2.WaitOne();
if (connection.Item1)
{
- connection.Item3.BeginTransaction();
+ SharedUtils.RetryOnException(() => connection.Item3.BeginTransaction());
DB_CONNECTIONS[DB_PATH] = new Tuple(true, connection.Item2, connection.Item3);
}
connection.Item2.ReleaseMutex();
@@ -66,39 +67,74 @@ public void BeginTransaction()
public int DeleteAll()
{
- return DB_CONNECTIONS[DB_PATH].Item3.DeleteAll();
+ try
+ {
+ return SharedUtils.RetryOnException(() => DB_CONNECTIONS[DB_PATH].Item3.DeleteAll());
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Failed to execute DB delete all!", e);
+ return -1;
+ }
}
public List ExecuteCommand(bool readOnly, SQLiteCommand cmd) where T : new()
{
- return cmd.ExecuteQuery();
+ try
+ {
+ return SharedUtils.RetryOnException(() => cmd.ExecuteQuery());
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Failed to execute DB execute command!", e);
+ return new List();
+ }
}
public int InsertOrReplace(object obj)
{
- // Not using DB_CONNECTIONS[DB_PATH].Item3.InsertOrReplace(obj); to prevent exceptions (https://github.com/praeclarum/sqlite-net/issues/761):
- BeginTransaction();
- DB_CONNECTIONS[DB_PATH].Item3.Delete(obj);
- int i = DB_CONNECTIONS[DB_PATH].Item3.Insert(obj);
- Commit();
- return i;
+ try
+ {
+ return SharedUtils.RetryOnException(() => DB_CONNECTIONS[DB_PATH].Item3.InsertOrReplace(obj)); ;
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Failed to execute DB insert or replace!", e);
+ return -1;
+ }
}
public int Insert(object obj)
{
- return DB_CONNECTIONS[DB_PATH].Item3.Insert(obj);
+ try
+ {
+ return SharedUtils.RetryOnException(() => DB_CONNECTIONS[DB_PATH].Item3.Insert(obj));
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Failed to execute DB insert!", e);
+ return -1;
+ }
}
public int InsertAll(IEnumerable