26using System.ComponentModel;
27using System.Diagnostics.CodeAnalysis;
28using System.Globalization;
29using System.Reflection;
75 internal sealed
class XmppService :
LoadableService, IXmppService, IDisposable
92 private Timer? reconnectTimer;
93 private string? domainName;
94 private string? accountName;
95 private string? passwordHash;
96 private string? passwordHashMethod;
97 private bool xmppConnected =
false;
98 private DateTime xmppLastStateChange = DateTime.MinValue;
100 private bool isCreatingClient;
102 private string? token =
null;
103 private DateTime tokenCreated = DateTime.MinValue;
104#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE
105 private const string debugRecipient =
"";
107#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE
114 #region Creation / Destruction
120 private async Task CreateXmppClient()
122 if (this.isCreatingClient)
127 this.isCreatingClient =
true;
129 if (!this.XmppParametersCurrent() || this.XmppStale())
131 if (this.xmppClient is not
null)
132 await this.DestroyXmppClient();
145 HostName = this.domainName;
160 this.xmppLastStateChange = DateTime.Now;
161 this.xmppConnected =
false;
163 Assembly AppAssembly =
App.
Current!.GetType().Assembly;
165 if (
string.IsNullOrEmpty(this.passwordHashMethod))
167 this.xmppClient =
new XmppClient(HostName, PortNumber, this.accountName, this.passwordHash,
172 this.xmppClient =
new XmppClient(HostName, PortNumber, this.accountName, this.passwordHash, this.passwordHashMethod,
176#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE
177 if (!
string.IsNullOrEmpty(debugRecipient))
180#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE
181 this.debugSniffer =
new RemoteSniffer(debugRecipient, DateTime.MaxValue,
this.xmppClient,
this.xmppClient,
185 this.xmppClient.Add(this.debugSniffer);
188 if (this.debugEventSink is not
null)
191 this.debugEventSink?.
Dispose();
192 this.debugEventSink =
null;
195 this.debugEventSink =
new EventFilter(
"Debug Event Filter",
196 new XmppEventSink(
"Debug Event Sink", this.xmppClient, debugRecipient,
false),
199 if (this.xmppClient is null || this.xmppClient.State != XmppState.Connected)
202 return string.IsNullOrEmpty(Event.StackTrace) || !Event.StackTrace.Contains(
"XmppEventSink");
218#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE
222 this.xmppClient.RequestRosterOnStartup =
false;
223 this.xmppClient.TrustServer = !IsIpAddress;
224 this.xmppClient.AllowCramMD5 =
false;
225 this.xmppClient.AllowDigestMD5 =
false;
226 this.xmppClient.AllowPlain =
false;
227 this.xmppClient.AllowEncryption =
true;
228 this.xmppClient.AllowScramSHA1 =
true;
229 this.xmppClient.AllowScramSHA256 =
true;
230 this.xmppClient.AllowQuickLogin =
true;
232 this.xmppClient.RequestRosterOnStartup =
true;
233 this.xmppClient.OnStateChanged += this.XmppClient_StateChanged;
234 this.xmppClient.OnConnectionError += this.XmppClient_ConnectionError;
235 this.xmppClient.OnError += this.XmppClient_Error;
236 this.xmppClient.OnChatMessage += this.XmppClient_OnChatMessage;
237 this.xmppClient.OnNormalMessage += this.XmppClient_OnNormalMessage;
238 this.xmppClient.OnPresenceSubscribe += this.XmppClient_OnPresenceSubscribe;
239 this.xmppClient.OnPresenceUnsubscribed += this.XmppClient_OnPresenceUnsubscribed;
240 this.xmppClient.OnRosterItemAdded += this.XmppClient_OnRosterItemAdded;
241 this.xmppClient.OnRosterItemUpdated += this.XmppClient_OnRosterItemUpdated;
242 this.xmppClient.OnRosterItemRemoved += this.XmppClient_OnRosterItemRemoved;
243 this.xmppClient.OnPresence += this.XmppClient_OnPresence;
248 this.xmppFilteredEventSink =
new EventFilter(
"XMPP Event Filter",
254 this.abuseClient =
new AbuseClient(this.xmppClient);
259 this.RegisterContractsEventHandlers();
261 if (!await this.contractsClient.
LoadKeys(
false))
265 Log.
Alert(
"Regeneration of keys not permitted at this time.",
266 string.Empty,
string.Empty,
string.Empty,
EventLevel.Major,
string.Empty,
string.Empty, Environment.StackTrace);
268 throw new Exception(
"Regeneration of keys not permitted at this time.");
271 await this.GenerateNewKeys();
285 ManagePresenceSubscriptionRequests =
false
288 this.provisioningClient.CanControlQuestion += this.ProvisioningClient_CanControlQuestion;
289 this.provisioningClient.CanReadQuestion += this.ProvisioningClient_CanReadQuestion;
290 this.provisioningClient.IsFriendQuestion += this.ProvisioningClient_IsFriendQuestion;
296 this.RegisterEDalerEventHandlers(this.eDalerClient);
302 this.RegisterNeuroFeatureEventHandlers(this.neuroFeaturesClient);
312 this.pepClient =
new PepClient(this.xmppClient);
313 this.ReregisterPepEventHandlers(this.pepClient);
315 this.httpxClient =
new HttpxClient(this.xmppClient, 8192);
318 this.IsLoggedOut =
false;
319 this.xmppClient.Connect(IsIpAddress ?
string.Empty : this.domainName);
320 this.RecreateReconnectTimer();
328 new KeyValuePair<string, object?>(
"Domain", this.domainName ??
string.Empty),
329 new KeyValuePair<string, object?>(
"Account", this.accountName ??
string.Empty),
337 this.isCreatingClient =
false;
342 private class RemoteLedgerWriter()
343 : TextWriter(CultureInfo.CurrentCulture)
345 private readonly StringBuilder sb =
new();
347 public override Encoding Encoding => Encoding.Unicode;
348 public override void Flush() => this.FlushAsync().Wait();
349 public override Task FlushAsync(CancellationToken cancellationToken) => this.FlushAsync();
351 public override async Task FlushAsync()
355 string s = this.sb.ToString();
356 string s2 = s.TrimStart();
357 if (
string.IsNullOrEmpty(s2))
369 int i = s2.IndexOf(
'<');
373 string[] Rows = s.Replace(
"\r\n",
"\n").Replace(
'\r',
'\n').Split(
'\n');
375 if (s2.StartsWith(
"<New", StringComparison.OrdinalIgnoreCase))
377 foreach (
string Row
in Rows)
380 else if (s2.StartsWith(
"<Update", StringComparison.OrdinalIgnoreCase))
382 foreach (
string Row
in Rows)
385 else if (s2.StartsWith(
"<Delete", StringComparison.OrdinalIgnoreCase))
387 foreach (
string Row
in Rows)
388 await Sniffer.
Error(Row);
390 else if (s2.StartsWith(
"<Clear", StringComparison.OrdinalIgnoreCase))
392 foreach (
string Row
in Rows)
397 foreach (
string Row
in Rows)
407 public override void Write(
char value) => this.sb.Append(value);
408 public override void Write(
char[]? buffer) => this.sb.Append(buffer);
409 public override void Write(
char[] buffer,
int index,
int count) => this.sb.Append(
new string(buffer, index, count));
410 public override void Write(ReadOnlySpan<char> buffer) => this.sb.Append(
new string(buffer));
411 public override void Write(
bool value) => this.sb.Append(value);
412 public override void Write(
int value) => this.sb.Append(value);
413 public override void Write(uint value) => this.sb.Append(value);
414 public override void Write(
long value) => this.sb.Append(value);
415 public override void Write(ulong value) => this.sb.Append(value);
416 public override void Write(
float value) => this.sb.Append(value);
417 public override void Write(
double value) => this.sb.Append(value);
418 public override void Write(decimal value) => this.sb.Append(value);
419 public override void Write(
string? value) => this.sb.Append(value);
420 public override void Write(
object? value) => this.sb.Append(value);
421 public override void Write(StringBuilder? value) => this.sb.Append(value);
422 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0) => this.sb.Append(
string.Format(this.FormatProvider, format, arg0));
423 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1) => this.sb.Append(
string.Format(this.FormatProvider, format, arg0, arg1));
424 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1,
object? arg2) => this.sb.Append(
string.Format(this.FormatProvider, format, arg0, arg1, arg2));
425 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format, params
object?[] arg) => this.sb.Append(
string.Format(this.FormatProvider, format, arg));
426 public override Task WriteAsync(
char value) { this.sb.Append(value);
return Task.CompletedTask; }
427 public override Task WriteAsync(
string? value) { this.sb.Append(value);
return Task.CompletedTask; }
428 public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken =
default) { this.sb.Append(value);
return Task.CompletedTask; }
429 public override Task WriteAsync(
char[] buffer,
int index,
int count) { this.sb.Append(
new string(buffer, index, count));
return Task.CompletedTask; }
430 public override Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken =
default) { this.sb.Append(buffer);
return Task.CompletedTask; }
431 public override void WriteLine() => this.sb.AppendLine(
string.Empty);
432 public override void WriteLine(
char value) => this.sb.AppendLine(value.ToString());
433 public override void WriteLine(
char[]? buffer) => this.sb.AppendLine(
new string(buffer));
434 public override void WriteLine(
char[] buffer,
int index,
int count) => this.sb.AppendLine(
new string(buffer, index, count));
435 public override void WriteLine(ReadOnlySpan<char> buffer) => this.sb.AppendLine(
new string(buffer));
436 public override void WriteLine(
bool value) => this.sb.AppendLine(value.ToString());
437 public override void WriteLine(
int value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
438 public override void WriteLine(uint value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
439 public override void WriteLine(
long value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
440 public override void WriteLine(ulong value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
441 public override void WriteLine(
float value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
442 public override void WriteLine(
double value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
443 public override void WriteLine(decimal value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
444 public override void WriteLine(
string? value) => this.sb.AppendLine(value?.
ToString());
445 public override void WriteLine(StringBuilder? value) => this.sb.AppendLine(value?.
ToString());
446 public override void WriteLine(
object? value) => this.sb.AppendLine(value?.
ToString());
447 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg0));
448 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg0, arg1));
449 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1,
object? arg2) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg0, arg1, arg2));
450 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format, params
object?[] arg) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg));
451 public override Task WriteLineAsync(
char value) { this.sb.AppendLine(value.ToString());
return Task.CompletedTask; }
452 public override Task WriteLineAsync(
string? value) { this.sb.AppendLine(value);
return Task.CompletedTask; }
453 public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken =
default) { this.sb.AppendLine(value?.
ToString());
return Task.CompletedTask; }
454 public override Task WriteLineAsync(
char[] buffer,
int index,
int count) { this.sb.AppendLine(
new string(buffer, index, count));
return Task.CompletedTask; }
455 public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken =
default) { this.sb.AppendLine(
new string(buffer.Span));
return Task.CompletedTask; }
456 public override Task WriteLineAsync() { this.sb.AppendLine(
string.Empty);
return Task.CompletedTask; }
460 private async Task DestroyXmppClient()
462 this.reconnectTimer?.Dispose();
463 this.reconnectTimer =
null;
465 await this.OnConnectionStateChanged(
XmppState.Offline);
467 if (this.xmppFilteredEventSink is not
null)
471 this.xmppFilteredEventSink.
Dispose();
472 this.xmppFilteredEventSink =
null;
475 this.contractsClient?.
Dispose();
476 this.contractsClient =
null;
478 this.fileUploadClient?.
Dispose();
479 this.fileUploadClient =
null;
481 this.thingRegistryClient?.
Dispose();
482 this.thingRegistryClient =
null;
484 this.provisioningClient?.
Dispose();
485 this.provisioningClient =
null;
488 this.eDalerClient =
null;
490 this.neuroFeaturesClient?.
Dispose();
491 this.neuroFeaturesClient =
null;
493 this.pushNotificationClient?.
Dispose();
494 this.pushNotificationClient =
null;
497 this.sensorClient =
null;
500 this.controlClient =
null;
502 this.concentratorClient?.
Dispose();
503 this.concentratorClient =
null;
506 this.pepClient =
null;
509 this.abuseClient =
null;
512 this.debugSniffer =
null;
515 if (this.debugEventSink is not
null)
518 this.debugEventSink?.
Dispose();
519 this.debugEventSink =
null;
522 this.xmppClient?.Dispose();
523 this.xmppClient =
null;
526 private bool XmppStale()
528 return this.xmppClient is
null ||
529 this.xmppClient.State == XmppState.Offline ||
530 this.xmppClient.State == XmppState.Error ||
531 (this.xmppClient.State != XmppState.Connected && (DateTime.Now - this.xmppLastStateChange).TotalSeconds >= 10);
534 private bool XmppParametersCurrent()
536 if (this.xmppClient is
null)
575 private void RecreateReconnectTimer()
577 this.reconnectTimer?.Dispose();
584 public void Dispose()
586 this.reconnectTimer?.Dispose();
587 this.reconnectTimer =
null;
589 if (this.xmppFilteredEventSink is not
null)
593 this.xmppFilteredEventSink.
Dispose();
594 this.xmppFilteredEventSink =
null;
597 this.contractsClient?.
Dispose();
598 this.contractsClient =
null;
600 this.fileUploadClient?.
Dispose();
601 this.fileUploadClient =
null;
603 this.thingRegistryClient?.
Dispose();
604 this.thingRegistryClient =
null;
606 this.provisioningClient?.
Dispose();
607 this.provisioningClient =
null;
610 this.eDalerClient =
null;
612 this.neuroFeaturesClient?.
Dispose();
613 this.neuroFeaturesClient =
null;
615 this.pushNotificationClient?.
Dispose();
616 this.pushNotificationClient =
null;
619 this.sensorClient =
null;
622 this.controlClient =
null;
624 this.concentratorClient?.
Dispose();
625 this.concentratorClient =
null;
628 this.pepClient =
null;
631 this.abuseClient =
null;
633 this.xmppClient?.Dispose();
634 this.xmppClient =
null;
673 public async Task<bool> WaitForConnectedState(TimeSpan Timeout)
675 if (this.xmppClient is
null)
677 DateTime Start = DateTime.Now;
679 while (this.xmppClient is
null && DateTime.Now - Start < Timeout)
680 await Task.Delay(1000);
682 if (this.xmppClient is
null)
685 Timeout -= DateTime.Now - Start;
688 if (this.xmppClient.State ==
XmppState.Connected)
691 if (Timeout < TimeSpan.Zero)
694 int i = await this.xmppClient.WaitStateAsync((
int)Timeout.TotalMilliseconds,
XmppState.Connected);
698 public override async Task Load(
bool IsResuming, CancellationToken CancellationToken)
700 if (this.
BeginLoad(IsResuming, CancellationToken))
704 ServiceRef.TagProfile.StepChanged += this.TagProfile_StepChanged;
705 ServiceRef.TagProfile.Changed += this.TagProfile_Changed;
708 await this.CreateXmppClient();
710 if ((this.xmppClient is not
null) &&
711 this.xmppClient.State ==
XmppState.Connected &&
715 _ = this.xmppClient.SetPresenceAsync(
Availability.Online);
729 public override Task Unload()
731 return this.Unload(
false);
734 public Task UnloadFast()
736 return this.Unload(
true);
739 private async Task Unload(
bool fast)
745 ServiceRef.TagProfile.StepChanged -= this.TagProfile_StepChanged;
746 ServiceRef.TagProfile.Changed -= this.TagProfile_Changed;
748 this.reconnectTimer?.Dispose();
749 this.reconnectTimer =
null;
751 if (this.xmppClient is not
null)
753 this.xmppClient.CheckConnection =
false;
771 await this.DestroyXmppClient();
782 private void TagProfile_StepChanged(
object? Sender, EventArgs e)
787 Task ExecutionTask = Task.Run(async () =>
793 if (CreateXmppClient && !this.XmppParametersCurrent())
794 await this.CreateXmppClient();
795 else if (!CreateXmppClient)
796 await this.DestroyXmppClient();
805 private void TagProfile_Changed(
object? Sender, PropertyChangedEventArgs e)
808 this.TagProfile_StepChanged(Sender,
new EventArgs());
811 private Task XmppClient_Error(
object? _, Exception e)
813 this.LatestError = e.Message;
814 return Task.CompletedTask;
817 private Task XmppClient_ConnectionError(
object? _, Exception e)
819 if (e is ObjectDisposedException)
822 this.LatestConnectionError = e.Message;
824 return Task.CompletedTask;
827 private async Task XmppClient_StateChanged(
object? Sender,
XmppState NewState)
829 this.xmppLastStateChange = DateTime.Now;
834 this.LatestError =
string.Empty;
835 this.LatestConnectionError =
string.Empty;
839 this.LatestError =
string.Empty;
840 this.LatestConnectionError =
string.Empty;
842 this.xmppConnected =
true;
844 this.RecreateReconnectTimer();
849 this.xmppClient?.PasswordHash ??
string.Empty,
850 this.xmppClient?.PasswordHashMethod ??
string.Empty);
858 this.RegisterContractsEventHandlers();
860 if (!await this.contractsClient.
LoadKeys(
false))
862 this.contractsClient.
Dispose();
863 this.contractsClient =
null;
877 ManagePresenceSubscriptionRequests =
false
880 this.provisioningClient.CanControlQuestion += this.ProvisioningClient_CanControlQuestion;
881 this.provisioningClient.CanReadQuestion += this.ProvisioningClient_CanReadQuestion;
882 this.provisioningClient.IsFriendQuestion += this.ProvisioningClient_IsFriendQuestion;
888 this.RegisterEDalerEventHandlers(this.eDalerClient);
894 this.RegisterNeuroFeatureEventHandlers(this.neuroFeaturesClient);
910 this.xmppConnected =
false;
912 if (this.xmppClient is not
null && !this.xmppClient.Disposed)
913 this.xmppClient.Reconnect();
918 await this.OnConnectionStateChanged(NewState);
924 public event StateChangedEventHandler? ConnectionStateChanged;
926 private async Task OnConnectionStateChanged(
XmppState NewState)
930 Task? T = this.ConnectionStateChanged?.Invoke(
this, NewState);
945 public bool IsLoggedOut {
get;
private set; }
946 public bool IsOnline => (this.xmppClient is not
null) && this.xmppClient.State ==
XmppState.Connected;
948 public string BareJid =>
this.xmppClient?.BareJID ??
string.Empty;
950 public string? LatestError {
get;
private set; }
951 public string? LatestConnectionError {
get;
private set; }
957 private enum ConnectOperation
960 ConnectAndCreateAccount,
964 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnect(
string domain,
bool isIpAddress,
string hostName,
int portNumber,
965 string languageCode, Assembly applicationAssembly, Func<XmppClient, Task> connectedFunc)
967 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber,
string.Empty,
string.Empty,
string.Empty, languageCode,
968 string.Empty,
string.Empty, applicationAssembly, connectedFunc, ConnectOperation.Connect);
971 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectAndCreateAccount(
string domain,
bool isIpAddress,
string hostName,
972 int portNumber,
string userName,
string password,
string languageCode,
string ApiKey,
string ApiSecret,
973 Assembly applicationAssembly, Func<XmppClient, Task> connectedFunc)
975 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber, userName, password,
string.Empty, languageCode,
976 ApiKey, ApiSecret, applicationAssembly, connectedFunc, ConnectOperation.ConnectAndCreateAccount);
979 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectAndConnectToAccount(
string domain,
bool isIpAddress,
string hostName,
980 int portNumber,
string userName,
string password,
string passwordMethod,
string languageCode, Assembly applicationAssembly,
981 Func<XmppClient, Task> connectedFunc)
983 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber, userName, password, passwordMethod, languageCode,
984 string.Empty,
string.Empty, applicationAssembly, connectedFunc, ConnectOperation.ConnectToAccount);
987 private async Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectInner(
string Domain,
bool IsIpAddress,
string HostName,
988 int PortNumber,
string UserName,
string Password,
string PasswordMethod,
string LanguageCode,
string ApiKey,
string ApiSecret,
989 Assembly ApplicationAssembly, Func<XmppClient, Task> ConnectedFunc, ConnectOperation Operation)
991 TaskCompletionSource<bool> Connected =
new();
993 string? ErrorMessage =
null;
994 bool StreamNegotiation =
false;
995 bool StreamOpened =
false;
996 bool StartingEncryption =
false;
997 bool Authenticating =
false;
998 bool Registering =
false;
999 bool IsTimeout =
false;
1000 string? ConnectionError =
null;
1001 string[]? Alternatives =
null;
1003 Task OnConnectionError(
object _, Exception e)
1005 if (e is ObjectDisposedException)
1008 Alternatives = ConflictInfo.Alternatives;
1010 ConnectionError = e.Message;
1012 Connected.TrySetResult(
false);
1013 return Task.CompletedTask;
1016 async Task OnStateChanged(
object _,
XmppState newState)
1021 StreamNegotiation =
true;
1025 StreamOpened =
true;
1029 StartingEncryption =
true;
1033 Authenticating =
true;
1035 if (Operation == ConnectOperation.Connect)
1036 Connected.TrySetResult(
true);
1045 Connected.TrySetResult(
true);
1049 Connected.TrySetResult(
false);
1056 Connected.TrySetResult(
false);
1064 if (
string.IsNullOrEmpty(PasswordMethod))
1065 Client =
new XmppClient(HostName, PortNumber, UserName, Password, LanguageCode, ApplicationAssembly, this.sniffer);
1067 Client =
new XmppClient(HostName, PortNumber, UserName, Password, PasswordMethod, LanguageCode, ApplicationAssembly, this.sniffer);
1069 if (Operation == ConnectOperation.ConnectAndCreateAccount)
1071 if (!
string.IsNullOrEmpty(ApiKey) && !
string.IsNullOrEmpty(ApiSecret))
1077 Client.TrustServer = !IsIpAddress;
1078 Client.AllowCramMD5 =
false;
1079 Client.AllowDigestMD5 =
false;
1080 Client.AllowPlain =
false;
1081 Client.AllowEncryption =
true;
1082 Client.AllowScramSHA1 =
true;
1083 Client.AllowScramSHA256 =
true;
1084 Client.AllowQuickLogin =
true;
1086 Client.OnConnectionError += OnConnectionError;
1087 Client.OnStateChanged += OnStateChanged;
1089 Client.
Connect(IsIpAddress ?
string.Empty : Domain);
1091 void TimerCallback(
object? _)
1094 Connected.TrySetResult(
false);
1098 Succeeded = await Connected.Task;
1100 if (Succeeded && (ConnectedFunc is not
null))
1101 await ConnectedFunc(Client);
1103 Client.OnStateChanged -= OnStateChanged;
1104 Client.OnConnectionError -= OnConnectionError;
1106 catch (Exception ex)
1108 ServiceRef.
LogService.LogException(ex,
new KeyValuePair<string, object?>(nameof(ConnectOperation), Operation.ToString()));
1118 if (!Succeeded &&
string.IsNullOrEmpty(ErrorMessage))
1120 if (this.sniffer is not
null)
1121 System.Diagnostics.Debug.WriteLine(
"Sniffer: ", await this.sniffer.SnifferToText());
1123 if (!StreamNegotiation || IsTimeout)
1125 else if (!StreamOpened)
1126 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.DomainIsNotAValidOperator), Domain];
1127 else if (!StartingEncryption)
1128 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.DomainDoesNotFollowEncryptionPolicy), Domain];
1129 else if (!Authenticating)
1130 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.UnableToAuthenticateWith), Domain];
1131 else if (!Registering)
1133 if (!
string.IsNullOrWhiteSpace(ConnectionError))
1134 ErrorMessage = ConnectionError;
1136 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.OperatorDoesNotSupportRegisteringNewAccounts), Domain];
1138 else if (Operation == ConnectOperation.ConnectAndCreateAccount)
1139 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.UsernameNameAlreadyTaken), this.accountName ??
string.Empty];
1140 else if (Operation == ConnectOperation.ConnectToAccount)
1141 ErrorMessage =
ServiceRef.
Localizer[nameof(AppResources.InvalidUsernameOrPassword), this.accountName ??
string.Empty];
1146 return (Succeeded, ErrorMessage, Alternatives);
1149 private void ReconnectTimer_Tick(
object? _)
1151 if (this.xmppClient is
null)
1157 if (this.XmppStale())
1159 this.xmppLastStateChange = DateTime.Now;
1161 if (!this.xmppClient.Disposed)
1162 this.xmppClient.Reconnect();
1175 public Task<bool> ChangePassword(
string NewPassword)
1177 TaskCompletionSource<bool> PasswordChanged =
new();
1181 PasswordChanged.TrySetResult(e.Ok);
1182 return Task.CompletedTask;
1185 return PasswordChanged.Task;
1190 #region Components & Services
1197 public Task<ServiceDiscoveryEventArgs> SendServiceDiscoveryRequest(
string FullJid)
1199 TaskCompletionSource<ServiceDiscoveryEventArgs> Result =
new();
1203 Result.TrySetResult(e);
1204 return Task.CompletedTask;
1215 public async Task<bool> DiscoverServices(
XmppClient? Client =
null)
1217 Client ??= this.xmppClient;
1228 catch (Exception ex)
1230 if (this.sniffer is not
null)
1232 string commsDump = await this.sniffer.SnifferToText();
1233 ServiceRef.
LogService.LogException(ex,
new KeyValuePair<string, object?>(
"Sniffer", commsDump));
1239 List<Task> Tasks = [];
1240 object SynchObject =
new();
1242 Tasks.Add(CheckFeatures(Client, SynchObject));
1245 Tasks.Add(CheckComponent(Client,
Item, SynchObject));
1247 await Task.WhenAll([.. Tasks]);
1270 private static async Task CheckFeatures(
XmppClient Client,
object SynchObject)
1280 private static async Task CheckComponent(
XmppClient Client,
Item Item,
object SynchObject)
1287 ServiceRef.TagProfile.LegalJid =
Item.
JID;
1290 ServiceRef.TagProfile.RegistryJid =
Item.
JID;
1296 ServiceRef.TagProfile.ProvisioningJid =
Item.
JID;
1306 ServiceRef.TagProfile.LogJid =
Item.
JID;
1309 ServiceRef.TagProfile.LogJid =
Item.
JID;
1312 ServiceRef.TagProfile.EDalerJid =
Item.
JID;
1315 ServiceRef.TagProfile.NeuroFeaturesJid =
Item.
JID;
1323 private async Task TransferIdDelivered(
object? Sender, MessageEventArgs e)
1331 bool Deleted =
XML.
Attribute(e.Content,
"deleted",
false);
1337 string[] Codes = CodesGenerated.Split(
CommonTypes.
CRLF, StringSplitOptions.RemoveEmptyEntries);
1339 if (Array.IndexOf<
string>(Codes, Code) < 0)
1342 await this.DestroyXmppClient();
1344 this.domainName =
string.Empty;
1345 this.accountName =
string.Empty;
1346 this.passwordHash =
string.Empty;
1347 this.passwordHashMethod =
string.Empty;
1348 this.xmppConnected =
false;
1361 public async Task AddTransferCode(
string Code)
1365 if (
string.IsNullOrEmpty(CodesGenerated))
1366 CodesGenerated = Code;
1368 CodesGenerated +=
"\r\n" + Code;
1376 #region Presence Subscriptions
1378 private async Task XmppClient_OnPresenceSubscribe(
object? Sender, PresenceEventArgs e)
1381 string FriendlyName =
string.IsNullOrWhiteSpace(e.NickName) ? e.FromBareJID : e.NickName;
1382 string? PhotoUrl =
null;
1384 int PhotoHeight = 0;
1386 foreach (XmlNode N
in e.Presence.ChildNodes)
1391 if (RemoteIdentity is not
null)
1400 Log.
Warning(
"Invalid ID received. Presence subscription declined.", e.FromBareJID, RemoteIdentity.
Id,
"IdValidationError",
1401 new KeyValuePair<string, object?>(
"Recipient JID",
this.BareJid),
1402 new KeyValuePair<string, object?>(
"Sender JID", e.FromBareJID),
1403 new KeyValuePair<string, object?>(
"Legal ID", RemoteIdentity.
Id),
1404 new KeyValuePair<string, object?>(
"Validation", Status));
1421 if (Info.
FriendlyName != FriendlyName || ((RemoteIdentity is not
null) && Info.
LegalId != RemoteIdentity.
Id))
1423 if (RemoteIdentity is not
null)
1425 Info.LegalId = RemoteIdentity.
Id;
1426 Info.LegalIdentity = RemoteIdentity;
1429 Info.FriendlyName = FriendlyName;
1436 if ((RemoteIdentity is not
null) && (RemoteIdentity.
Attachments is not
null))
1438 (PhotoUrl, PhotoWidth, PhotoHeight) = await PhotosLoader.LoadPhotoAsTemporaryFile(RemoteIdentity.
Attachments,
1457 AllowSubscriptionFrom =
true,
1458 BareJid = e.FromBareJID,
1459 FriendlyName =
string.IsNullOrWhiteSpace(e.NickName) ? e.FromBareJID : e.NickName,
1467 Info.AllowSubscriptionFrom =
true;
1481 if (SubscribeTo.HasValue && SubscribeTo.Value)
1486 IdXml =
string.Empty;
1489 StringBuilder Xml =
new();
1491 IdXml = Xml.ToString();
1494 e.Client.RequestPresenceSubscription(e.FromBareJID, IdXml);
1502 if (this.abuseClient is
null)
1517 AllowSubscriptionFrom =
false,
1518 BareJid = e.FromBareJID,
1519 FriendlyName =
string.IsNullOrWhiteSpace(e.NickName) ? e.FromBareJID : e.NickName,
1527 Info.AllowSubscriptionFrom =
false;
1541 TaskCompletionSource<bool> Result =
new();
1545 Result.TrySetResult(e.Ok);
1546 return Task.CompletedTask;
1561 private async Task XmppClient_OnPresenceUnsubscribed(
object? Sender, PresenceEventArgs e)
1566 ContactInfo.AllowSubscriptionFrom =
null;
1573 #region IQ Stanzas (Information Query)
1583 public Task<XmlElement> IqSetAsync(
string To,
string Xml)
1595 if (this.xmppClient is
null)
1596 throw new Exception(
"Not connected to XMPP network.");
1598 return this.xmppClient;
1621 public void SendMessage(
QoSLevel QoS,
Waher.
Networking.
XMPP.MessageType Type,
string Id,
string To,
string CustomXml,
string Body,
1622 string Subject,
string Language,
string ThreadId,
string ParentThreadId, DeliveryEventHandler? DeliveryCallback,
object? State)
1625 QoS, Type, Id, To, CustomXml, Body, Subject, Language, ThreadId, ParentThreadId, DeliveryCallback, State);
1628 private Task XmppClient_OnNormalMessage(
object? Sender, MessageEventArgs e)
1630 Log.
Warning(
"Unhandled message received.", e.To, e.From,
1631 new KeyValuePair<string, object?>(
"Stanza", e.Message.OuterXml));
1633 return Task.CompletedTask;
1636 private async Task XmppClient_OnChatMessage(
object? Sender, MessageEventArgs e)
1638 string RemoteBareJid = e.FromBareJID;
1640 foreach (XmlNode N
in e.Message.ChildNodes)
1642 if (N is XmlElement E &&
1643 E.LocalName ==
"qlRef" &&
1645 RemoteBareJid.IndexOf(
'@') < 0 &&
1646 RemoteBareJid.IndexOf(
'/') < 0)
1650 foreach (XmlNode N2
in E.ChildNodes)
1652 if (N2 is XmlElement E2 &&
1653 E2.LocalName ==
"identity" &&
1661 if (RemoteIdentity is not
null)
1663 IdentityStatus Status = await this.ValidateIdentity(RemoteIdentity);
1666 Log.
Warning(
"Message rejected because the embedded legal identity was not valid.",
1667 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1668 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1669 new KeyValuePair<string, object?>(
"Status", Status));
1673 string Jid = RemoteIdentity[
"JID"];
1675 if (
string.IsNullOrEmpty(Jid))
1677 Log.
Warning(
"Message rejected because the embedded legal identity lacked JID.",
1678 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1679 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1680 new KeyValuePair<string, object?>(
"Status", Status));
1684 if (!
string.Equals(
XML.
Attribute(E,
"bareJid",
string.Empty), Jid, StringComparison.OrdinalIgnoreCase))
1686 Log.
Warning(
"Message rejected because the embedded legal identity had a different JID compared to the JID of the quick-login reference.",
1687 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1688 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1689 new KeyValuePair<string, object?>(
"Status", Status));
1693 RemoteBareJid = Jid;
1700 string? ReplaceObjectId =
null;
1705 RemoteBareJid = RemoteBareJid,
1706 RemoteObjectId = e.Id,
1708 Html =
string.Empty,
1710 Markdown = string.Empty
1713 foreach (XmlNode N
in e.Message.ChildNodes)
1715 if (N is XmlElement E)
1717 switch (N.LocalName)
1720 if (E.NamespaceURI ==
"urn:xmpp:content")
1726 case "text/markdown":
1727 Message.Markdown = E.InnerText;
1731 Message.PlainText = E.InnerText;
1735 Message.Html = E.InnerText;
1742 if (E.NamespaceURI ==
"http://jabber.org/protocol/xhtml-im")
1744 string Html = E.InnerXml;
1746 int i = Html.IndexOf(
"<body", StringComparison.OrdinalIgnoreCase);
1749 i = Html.IndexOf(
'>', i + 5);
1751 Html = Html[(i + 1)..].TrimStart();
1753 i = Html.LastIndexOf(
"</body>", StringComparison.OrdinalIgnoreCase);
1755 Html = Html[..i].TrimEnd();
1758 Message.Html = Html;
1763 if (E.NamespaceURI ==
"urn:xmpp:message-correct:0")
1769 E.HasAttribute(
"stamp") &&
1770 XML.
TryParse(E.GetAttribute(
"stamp"), out DateTime Timestamp2))
1772 Message.Created = Timestamp2.ToUniversalTime();
1779 if (!
string.IsNullOrEmpty(Message.
Markdown))
1785 AllowScriptTag =
false,
1786 EmbedEmojis =
false,
1787 AudioAutoplay =
false,
1788 AudioControls =
false,
1789 ParseMetaData =
false,
1790 VideoAutoplay =
false,
1791 VideoControls =
false
1796 if (
string.IsNullOrEmpty(Message.
PlainText))
1799 if (
string.IsNullOrEmpty(Message.
Html))
1802 catch (Exception ex)
1805 Message.Markdown =
string.Empty;
1809 if (
string.IsNullOrEmpty(ReplaceObjectId))
1819 ReplaceObjectId =
null;
1824 Old.Updated = Message.
Created;
1825 Old.Html = Message.
Html;
1835 MainThread.BeginInvokeOnMainThread(async () =>
1839 string.Equals(
ChatViewModel.BareJid, RemoteBareJid, StringComparison.OrdinalIgnoreCase))
1841 if (
string.IsNullOrEmpty(ReplaceObjectId))
1850 ReplaceObjectId = ReplaceObjectId,
1851 BareJid = RemoteBareJid,
1852 Category = RemoteBareJid
1858 private Task ClientMessage(
object? Sender, MessageEventArgs e)
1862 string Message = e.Body;
1864 if (!
string.IsNullOrEmpty(Code))
1870 if (!
string.IsNullOrEmpty(LocalizedMessage))
1871 Message = LocalizedMessage;
1879 MainThread.BeginInvokeOnMainThread(async () =>
1881 switch (Type.ToUpperInvariant())
1885 await ServiceRef.UiService.DisplayAlert(
1886 ServiceRef.Localizer[nameof(AppResources.Information)], Message,
1887 ServiceRef.Localizer[nameof(AppResources.Ok)]);
1893 await ServiceRef.UiService.DisplayAlert(
1894 ServiceRef.Localizer[nameof(AppResources.ErrorTitle)], Message,
1895 ServiceRef.Localizer[nameof(AppResources.Ok)]);
1901 return Task.CompletedTask;
1908 private async Task XmppClient_OnPresence(
object? Sender, PresenceEventArgs e)
1912 Task? T = this.OnPresence?.Invoke(
this, e);
1916 catch (Exception ex)
1925 public event PresenceEventHandlerAsync? OnPresence;
1931 public void RequestPresenceSubscription(
string BareJid)
1941 public void RequestPresenceSubscription(
string BareJid,
string CustomXml)
1950 public void RequestPresenceUnsubscription(
string BareJid)
1959 public void RequestRevokePresenceSubscription(
string BareJid)
1971 public RosterItem[] Roster => this.xmppClient?.Roster ?? [];
1978 public RosterItem? GetRosterItem(
string BareJid)
1996 public void RemoveRosterItem(
string BareJid)
2001 private async Task XmppClient_OnRosterItemAdded(
object? Sender,
RosterItem Item)
2005 Task? T = this.OnRosterItemAdded?.Invoke(
this,
Item);
2009 catch (Exception ex)
2018 public event RosterItemEventHandlerAsync? OnRosterItemAdded;
2020 private async Task XmppClient_OnRosterItemUpdated(
object? Sender,
RosterItem Item)
2024 Task? T = this.OnRosterItemUpdated?.Invoke(
this,
Item);
2028 catch (Exception ex)
2037 public event RosterItemEventHandlerAsync? OnRosterItemUpdated;
2039 private async Task XmppClient_OnRosterItemRemoved(
object? Sender,
RosterItem Item)
2043 Task? T = this.OnRosterItemRemoved?.Invoke(
this,
Item);
2047 catch (Exception ex)
2056 public event RosterItemEventHandlerAsync? OnRosterItemRemoved;
2060 #region Push Notification
2065 public bool SupportsPushNotification => this.pushNotificationClient is not
null;
2075 if (this.pushNotificationClient is
null)
2076 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.PushNotificationServiceNotFound)]);
2078 return this.pushNotificationClient;
2091 if (this.pushNotificationClient is
null || !this.IsOnline ||
string.IsNullOrEmpty(
TokenInformation.
Token))
2115 public Task ClearPushNotificationRules()
2131 string Channel,
string MessageVariable,
string PatternMatchingScript,
string ContentScript)
2134 PatternMatchingScript, ContentScript);
2148 public async Task<string?> GetApiToken(
int Seconds)
2150 DateTime Now = DateTime.UtcNow;
2152 if (!
string.IsNullOrEmpty(this.token) && Now.Subtract(
this.tokenCreated).TotalSeconds < Seconds - 10)
2157 if (!await this.WaitForConnectedState(TimeSpan.FromSeconds(20)))
2161 if (this.httpxClient is
null)
2162 throw new Exception(
"Not connected to XMPP network.");
2165 this.tokenCreated = Now;
2179 public async Task<object> PostToProtectedApi(
string LocalResource,
object Data, params KeyValuePair<string, string>[] Headers)
2181 StringBuilder Url =
new();
2184 Url.Append(
"httpx://");
2185 else if (!
string.IsNullOrEmpty(this.token))
2187 Url.Append(
"https://");
2189 KeyValuePair<string, string> Authorization =
new(
"Authorization",
"Bearer " + this.token);
2191 if (Headers is
null)
2192 Headers = [Authorization];
2195 int c = Headers.Length;
2197 Array.Resize(ref Headers, c + 1);
2198 Headers[c] = Authorization;
2202 throw new IOException(
"No connection and no token available for call to protect API.");
2205 Url.Append(LocalResource);
2212 #region HTTP File Upload
2222 if (this.fileUploadClient is
null)
2223 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.FileUploadServiceNotFound)]);
2225 return this.fileUploadClient;
2232 public bool FileUploadIsSupported
2238 return ServiceRef.TagProfile.FileUploadIsSupported &&
2239 this.fileUploadClient is not
null &&
2242 catch (Exception ex)
2256 public Task<HttpFileUploadEventArgs> RequestUploadSlotAsync(
string FileName,
string ContentType,
long ContentSize)
2258 return this.FileUploadClient.RequestUploadSlotAsync(FileName, ContentType, ContentSize);
2264 #region Personal Eventing Protocol (PEP)
2266 private readonly LinkedList<KeyValuePair<Type, PersonalEventNotificationEventHandler>> pepHandlers =
new();
2276 if (this.pepClient is
null)
2277 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.PepServiceNotFound)]);
2279 return this.pepClient;
2288 public void RegisterPepHandler(Type PersonalEventType, PersonalEventNotificationEventHandler Handler)
2290 lock (this.pepHandlers)
2292 this.pepHandlers.AddLast(
new KeyValuePair<Type, PersonalEventNotificationEventHandler>(PersonalEventType, Handler));
2304 public bool UnregisterPepHandler(Type PersonalEventType, PersonalEventNotificationEventHandler Handler)
2306 lock (this.pepHandlers)
2308 LinkedListNode<KeyValuePair<Type, PersonalEventNotificationEventHandler>>? Node = this.pepHandlers.First;
2310 while (Node is not
null)
2312 if (Node.Value.Key == PersonalEventType &&
2313 (Node.Value.Value.Target?.Equals(Handler.Target) ?? Handler.Target is
null) &&
2314 Node.Value.Value.Method.Equals(Handler.Method))
2316 this.pepHandlers.Remove(Node);
2329 lock (this.pepHandlers)
2331 foreach (KeyValuePair<Type, PersonalEventNotificationEventHandler> P
in this.pepHandlers)
2338 #region Thing Registries & Discovery
2348 if (this.thingRegistryClient is
null)
2349 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.ThingRegistryServiceNotFound)]);
2351 return this.thingRegistryClient;
2365 public bool IsIoTDiscoClaimURI(
string DiscoUri)
2375 public bool IsIoTDiscoSearchURI(
string DiscoUri)
2385 public bool IsIoTDiscoDirectURI(
string DiscoUri)
2396 public bool TryDecodeIoTDiscoClaimURI(
string DiscoUri, [NotNullWhen(
true)] out
MetaDataTag[]? Tags)
2408 public bool TryDecodeIoTDiscoSearchURI(
string DiscoUri, [NotNullWhen(
true)] out
SearchOperator[]? Operators,
2409 out
string? RegistryJid)
2416 List<SearchOperator> List = [];
2420 if (Operator.Name.Equals(
"R", StringComparison.OrdinalIgnoreCase))
2422 if (!
string.IsNullOrEmpty(RegistryJid))
2428 RegistryJid = StrEqOp.Value;
2434 Operators = [.. List];
2449 public bool TryDecodeIoTDiscoDirectURI(
string DiscoUri, [NotNullWhen(
true)] out
string? Jid, out
string? SourceId, out
string? NodeId,
2450 out
string? PartitionId, [NotNullWhen(
true)] out
MetaDataTag[]? Tags)
2463 List<MetaDataTag> TagsFound = [];
2469 switch (S.Name.ToUpper(CultureInfo.InvariantCulture))
2484 PartitionId = S.Value;
2501 Tags = [.. TagsFound];
2503 return !
string.IsNullOrEmpty(Jid);
2512 public Task<NodeResultEventArgs> ClaimThing(
string DiscoUri,
bool MakePublic)
2514 if (!this.TryDecodeIoTDiscoClaimURI(DiscoUri, out
MetaDataTag[]? Tags))
2515 throw new ArgumentException(
ServiceRef.
Localizer[nameof(AppResources.InvalidIoTDiscoClaimUri)], nameof(DiscoUri));
2517 TaskCompletionSource<NodeResultEventArgs> Result =
new();
2521 Result.TrySetResult(e);
2522 return Task.CompletedTask;
2537 public Task<bool> Disown(
string RegistryJid,
string ThingJid,
string SourceId,
string Partition,
string NodeId)
2539 TaskCompletionSource<bool> Result =
new();
2543 Result.TrySetResult(e.Ok);
2544 return Task.CompletedTask;
2557 public async Task<(
SearchResultThing[],
string?, bool)> Search(
int Offset,
int MaxCount,
string DiscoUri)
2559 if (!this.TryDecodeIoTDiscoSearchURI(DiscoUri, out
SearchOperator[]? Operators, out
string? RegistryJid))
2562 (
SearchResultThing[] Things,
bool More) = await this.Search(Offset, MaxCount, RegistryJid, Operators);
2564 return (Things, RegistryJid, More);
2582 Result.TrySetResult((e.Things, e.More));
2584 Result.TrySetException(e.StanzaError ?? new Exception(
"Unable to perform search."));
2586 return Task.CompletedTask;
2599 if (!this.TryDecodeIoTDiscoSearchURI(DiscoUri, out
SearchOperator[]? Operators, out
string? RegistryJid))
2604 return (Things, RegistryJid);
2613 public async Task<SearchResultThing[]> SearchAll(
string? RegistryJid, params
SearchOperator[] Operators)
2619 List<SearchResultThing> Result = [];
2620 int Offset = Things.Length;
2622 Result.AddRange(Things);
2627 Result.AddRange(Things);
2628 Offset += Things.Length;
2636 #region Legal Identities
2641 public async Task GenerateNewKeys()
2653 public async Task<IdApplicationAttributesEventArgs> GetIdApplicationAttributes()
2665 public async Task<LegalIdentity> AddLegalIdentity(
RegisterIdentityModel Model,
bool GenerateNewKeys,
2668 if (GenerateNewKeys)
2669 await this.GenerateNewKeys();
2679 throw e2.StanzaError ??
new Exception(e2.
ErrorText);
2697 public async Task<LegalIdentity[]> GetLegalIdentities(
XmppClient? client =
null)
2731 return (Info is not
null && Info.
LegalIdentity is not
null);
2770 public async Task PetitionIdentity(
CaseInsensitiveString LegalId,
string PetitionId,
string Purpose)
2773 throw new Exception(
"No Legal Identity registered.");
2777 this.StartPetition(PetitionId);
2781 private void StartPetition(
string PetitionId)
2783 lock (this.currentPetitions)
2785 this.currentPetitions[PetitionId] =
true;
2789 private bool EndPetition(
string PetitionId)
2791 lock (this.currentPetitions)
2793 return this.currentPetitions.Remove(PetitionId);
2804 public Task SendPetitionIdentityResponse(
CaseInsensitiveString LegalId,
string PetitionId,
string RequestorFullJid,
bool Response)
2812 public event LegalIdentityEventHandler? LegalIdentityChanged;
2817 public event LegalIdentityEventHandler? IdentityApplicationChanged;
2819 private async Task ContractsClient_IdentityUpdated(
object? Sender, LegalIdentityEventArgs e)
2829 this.LegalIdentityChanged?.Invoke(
this, e);
2833 MainThread.BeginInvokeOnMainThread(async () =>
2841 catch (Exception ex)
2854 if (e.Identity.IsDiscarded())
2857 this.IdentityApplicationChanged?.Invoke(
this, e);
2859 else if (e.Identity.IsApproved())
2866 this.LegalIdentityChanged?.Invoke(
this, e);
2867 this.IdentityApplicationChanged?.Invoke(
this, e);
2869 if (ToObsolete is not
null && !ToObsolete.IsDiscarded())
2870 await this.ObsoleteLegalIdentity(ToObsolete.
Id);
2875 this.IdentityApplicationChanged?.Invoke(
this, e);
2880 if (e.Identity.IsDiscarded())
2884 this.LegalIdentityChanged?.Invoke(
this, e);
2887 catch (Exception ex)
2897 public event LegalIdentityPetitionEventHandler? PetitionForIdentityReceived;
2899 private async Task ContractsClient_PetitionForIdentityReceived(
object? Sender, LegalIdentityPetitionEventArgs e)
2903 this.PetitionForIdentityReceived?.Invoke(
this, e);
2905 catch (Exception ex)
2915 public event LegalIdentityPetitionResponseEventHandler? PetitionedIdentityResponseReceived;
2917 private async Task ContractsClient_PetitionedIdentityResponseReceived(
object? Sender, LegalIdentityPetitionResponseEventArgs e)
2921 this.EndPetition(e.PetitionId);
2922 this.PetitionedIdentityResponseReceived?.Invoke(
this, e);
2924 catch (Exception ex)
2935 public Task ExportSigningKeys(XmlWriter Output)
2945 public Task<bool> ImportSigningKeys(XmlElement Xml)
2962 #region Smart Contracts
2964 private readonly Dictionary<CaseInsensitiveString, DateTime> lastContractEvent = [];
2974 if (this.contractsClient is
null)
2975 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.LegalServiceNotFound)]);
2977 return this.contractsClient;
2981 private void RegisterContractsEventHandlers()
2985 this.ContractsClient.IdentityUpdated += this.ContractsClient_IdentityUpdated;
2986 this.ContractsClient.PetitionForIdentityReceived += this.ContractsClient_PetitionForIdentityReceived;
2987 this.ContractsClient.PetitionedIdentityResponseReceived += this.ContractsClient_PetitionedIdentityResponseReceived;
2988 this.ContractsClient.PetitionForContractReceived += this.ContractsClient_PetitionForContractReceived;
2989 this.ContractsClient.PetitionedContractResponseReceived += this.ContractsClient_PetitionedContractResponseReceived;
2990 this.ContractsClient.PetitionForSignatureReceived += this.ContractsClient_PetitionForSignatureReceived;
2991 this.ContractsClient.PetitionedSignatureResponseReceived += this.ContractsClient_PetitionedSignatureResponseReceived;
2992 this.ContractsClient.PetitionForPeerReviewIDReceived += this.ContractsClient_PetitionForPeerReviewIdReceived;
2993 this.ContractsClient.PetitionedPeerReviewIDResponseReceived += this.ContractsClient_PetitionedPeerReviewIdResponseReceived;
2994 this.ContractsClient.PetitionClientUrlReceived += this.ContractsClient_PetitionClientUrlReceived;
2995 this.ContractsClient.ContractProposalReceived += this.ContractsClient_ContractProposalReceived;
2996 this.ContractsClient.ContractUpdated += this.ContractsClient_ContractUpdated;
2997 this.ContractsClient.ContractSigned += this.ContractsClient_ContractSigned;
3014 public async Task<string[]> GetCreatedContractReferences()
3016 List<string> Result = [];
3017 string[] ContractIds;
3024 Result.AddRange(ContractIds);
3025 Nr = ContractIds.Length;
3037 public async Task<string[]> GetSignedContractReferences()
3039 List<string> Result = [];
3040 string[] ContractIds;
3047 Result.AddRange(ContractIds);
3048 Nr = ContractIds.Length;
3069 lock (this.currentTransactions)
3072 string Currency =
Contract[
"Currency"]?.ToString() ??
string.Empty;
3079 await UpdateContractReference(Result);
3091 await UpdateContractReference(Result);
3110 public async Task<Contract> CreateContract(
3119 DateTime? SignAfter,
3120 DateTime? SignBefore,
3121 bool CanActAsTemplate)
3123 Contract Result = await this.
ContractsClient.
CreateContractAsync(TemplateId, Parts,
Parameters, Visibility, PartsMode,
Duration, ArchiveRequired, ArchiveOptional, SignAfter, SignBefore, CanActAsTemplate);
3124 await UpdateContractReference(Result);
3148 this.StartPetition(PetitionId);
3159 public Task SendPetitionContractResponse(
CaseInsensitiveString ContractId,
string PetitionId,
string RequestorFullJid,
bool Response)
3167 public event ContractPetitionEventHandler? PetitionForContractReceived;
3169 private async Task ContractsClient_PetitionForContractReceived(
object? Sender, ContractPetitionEventArgs e)
3173 this.PetitionForContractReceived?.Invoke(
this, e);
3175 catch (Exception ex)
3185 public event ContractPetitionResponseEventHandler? PetitionedContractResponseReceived;
3187 private async Task ContractsClient_PetitionedContractResponseReceived(
object? Sender, ContractPetitionResponseEventArgs e)
3191 this.EndPetition(e.PetitionId);
3192 this.PetitionedContractResponseReceived?.Invoke(
this, e);
3194 catch (Exception ex)
3208 lock (this.lastContractEvent)
3210 if (this.lastContractEvent.TryGetValue(ContractId, out DateTime TP))
3213 return DateTime.MinValue;
3226 ContractId = Contract.ContractId
3244 public event ContractProposalEventHandler? ContractProposalReceived;
3246 private async Task ContractsClient_ContractProposalReceived(
object? Sender, ContractProposalEventArgs e)
3250 this.ContractProposalReceived?.Invoke(
this, e);
3252 catch (Exception ex)
3262 public event ContractReferenceEventHandler? ContractUpdated;
3264 private async Task ContractsClient_ContractUpdated(
object? Sender, ContractReferenceEventArgs e)
3266 await this.ContractUpdatedOrSigned(e);
3270 this.ContractUpdated?.Invoke(
this, e);
3272 catch (Exception ex)
3278 private Task ContractUpdatedOrSigned(ContractReferenceEventArgs e)
3280 lock (this.lastContractEvent)
3282 this.lastContractEvent[e.ContractId] = DateTime.Now;
3285 return Task.CompletedTask;
3291 public event ContractSignedEventHandler? ContractSigned;
3293 private async Task ContractsClient_ContractSigned(
object? Sender, ContractSignedEventArgs e)
3295 await this.ContractUpdatedOrSigned(e);
3299 this.ContractSigned?.Invoke(
this, e);
3301 catch (Exception ex)
3330 public Task<KeyValuePair<string, TemporaryFile>> GetAttachment(
string Url,
SignWith SignWith, TimeSpan Timeout)
3350 this.StartPetition(PetitionId);
3369 public event SignaturePetitionEventHandler? PetitionForPeerReviewIdReceived;
3371 private async Task ContractsClient_PetitionForPeerReviewIdReceived(
object? Sender, SignaturePetitionEventArgs e)
3375 this.PetitionForPeerReviewIdReceived?.Invoke(
this, e);
3377 catch (Exception ex)
3387 public event SignaturePetitionResponseEventHandler? PetitionedPeerReviewIdResponseReceived;
3389 private async Task ContractsClient_PetitionedPeerReviewIdResponseReceived(
object? Sender, SignaturePetitionResponseEventArgs e)
3393 this.EndPetition(e.PetitionId);
3394 this.PetitionedPeerReviewIdResponseReceived?.Invoke(
this, e);
3396 catch (Exception ex)
3407 public async Task<ServiceProviderWithLegalId[]> GetServiceProvidersForPeerReviewAsync()
3418 public async Task SelectPeerReviewService(
string ServiceId,
string ServiceProvider)
3423 private readonly Dictionary<string, bool> currentPetitions = [];
3425 private async Task ContractsClient_PetitionClientUrlReceived(
object? Sender, PetitionClientUrlEventArgs e)
3427 lock (this.currentPetitions)
3429 if (!this.currentPetitions.ContainsKey(e.PetitionId))
3431 ServiceRef.
LogService.LogWarning(
"Client URL message for a petition is ignored. Petition ID not recognized.",
3432 new KeyValuePair<string, object?>(
"PetitionId", e.PetitionId),
3433 new KeyValuePair<string, object?>(
"ClientUrl", e.ClientUrl));
3451 public Task<byte[]> Sign(
byte[] data,
SignWith signWith)
3465 public bool? ValidateSignature(
LegalIdentity legalIdentity,
byte[] data,
byte[] signature)
3480 public Task SendPetitionSignatureResponse(
CaseInsensitiveString LegalId,
byte[] Content,
byte[]
Signature,
string PetitionId,
string RequestorFullJid,
bool Response)
3488 public event SignaturePetitionEventHandler? PetitionForSignatureReceived;
3490 private async Task ContractsClient_PetitionForSignatureReceived(
object? Sender, SignaturePetitionEventArgs e)
3494 this.PetitionForSignatureReceived?.Invoke(
this, e);
3496 catch (Exception ex)
3506 public event SignaturePetitionResponseEventHandler? SignaturePetitionResponseReceived;
3508 private async Task ContractsClient_PetitionedSignatureResponseReceived(
object? Sender, SignaturePetitionResponseEventArgs e)
3512 this.EndPetition(e.PetitionId);
3513 this.SignaturePetitionResponseReceived?.Invoke(
this, e);
3515 catch (Exception ex)
3524 #region Provisioning
3534 if (this.provisioningClient is
null)
3535 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.ProvisioningServiceNotFound)]);
3537 return this.provisioningClient;
3541 private async Task ProvisioningClient_IsFriendQuestion(
object? Sender, IsFriendEventArgs e)
3543 if (e.From.IndexOfAny(clientChars) < 0)
3547 private async Task ProvisioningClient_CanReadQuestion(
object? Sender, CanReadEventArgs e)
3549 if (e.From.IndexOfAny(clientChars) < 0)
3553 private async Task ProvisioningClient_CanControlQuestion(
object? Sender, CanControlEventArgs e)
3555 if (e.From.IndexOfAny(clientChars) < 0)
3559 private static readonly
char[] clientChars = [
'@',
'/'];
3577 public void IsFriendResponse(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool IsFriend,
3578 RuleRange Range, IqResultEventHandlerAsync Callback,
object? State)
3595 public void CanControlResponseAll(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool CanControl,
3596 string[]? ParameterNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3599 Node, Callback, State);
3614 public void CanControlResponseCaller(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3615 bool CanControl,
string[]? ParameterNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3618 ParameterNames, Node, Callback, State);
3633 public void CanControlResponseDomain(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3634 bool CanControl,
string[]? ParameterNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3637 ParameterNames, Node, Callback, State);
3653 public void CanControlResponseDevice(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3654 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, IqResultEventHandlerAsync Callback,
3658 ParameterNames,
Token, Node, Callback, State);
3674 public void CanControlResponseService(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3675 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, IqResultEventHandlerAsync Callback,
3679 ParameterNames,
Token, Node, Callback, State);
3695 public void CanControlResponseUser(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3696 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, IqResultEventHandlerAsync Callback,
3700 ParameterNames,
Token, Node, Callback, State);
3716 public void CanReadResponseAll(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool CanRead,
3717 FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3720 Node, Callback, State);
3736 public void CanReadResponseCaller(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3737 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3740 FieldTypes, FieldNames, Node, Callback, State);
3756 public void CanReadResponseDomain(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3757 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, IqResultEventHandlerAsync Callback,
object? State)
3760 FieldTypes, FieldNames, Node, Callback, State);
3777 public void CanReadResponseDevice(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3782 FieldTypes, FieldNames,
Token, Node, Callback, State);
3799 public void CanReadResponseService(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3804 FieldTypes, FieldNames,
Token, Node, Callback, State);
3821 public void CanReadResponseUser(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
3826 FieldTypes, FieldNames,
Token, Node, Callback, State);
3839 public void DeleteDeviceRules(
string ServiceJID,
string DeviceJID,
string NodeId,
string SourceId,
string Partition,
3840 IqResultEventHandlerAsync Callback,
object? State)
3857 if (this.sensorClient is
null)
3858 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.SensorServiceNotFound)]);
3860 return this.sensorClient;
3872 if (this.controlClient is
null)
3873 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.ControlServiceNotFound)]);
3875 return this.controlClient;
3887 if (this.concentratorClient is
null)
3888 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.ConcentratorServiceNotFound)]);
3890 return this.concentratorClient;
3907 Result.TrySetResult((e.Things, e.More));
3909 Result.TrySetException(e.StanzaError ??
new Exception(
ServiceRef.
Localizer[nameof(AppResources.UnableToGetListOfMyDevices)]));
3911 return Task.CompletedTask;
3921 public async Task<SearchResultThing[]> GetAllMyDevices()
3927 List<SearchResultThing> Result = [];
3928 int Offset = Things.Length;
3930 Result.AddRange(Things);
3935 Result.AddRange(Things);
3936 Offset += Things.Length;
3950 public void GetCertificate(
string Token, CertificateCallback Callback,
object? State)
3963 public void GetControlForm(
string To,
string Language, DataFormResultEventHandler Callback,
object? State,
3996 private readonly Dictionary<string, Wallet.Transaction> currentTransactions = [];
3997 private Balance? lastBalance =
null;
3998 private DateTime lastEDalerEvent = DateTime.MinValue;
4008 if (this.eDalerClient is
null)
4009 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.EDalerServiceNotFound)]);
4011 return this.eDalerClient;
4015 private void RegisterEDalerEventHandlers(
EDalerClient Client)
4017 Client.BalanceUpdated += this.EDalerClient_BalanceUpdated;
4018 Client.BuyEDalerOptionsClientUrlReceived += this.NeuroWallet_BuyEDalerOptionsClientUrlReceived;
4019 Client.BuyEDalerOptionsCompleted += this.NeuroWallet_BuyEDalerOptionsCompleted;
4020 Client.BuyEDalerOptionsError += this.NeuroWallet_BuyEDalerOptionsError;
4021 Client.BuyEDalerClientUrlReceived += this.NeuroWallet_BuyEDalerClientUrlReceived;
4022 Client.BuyEDalerCompleted += this.NeuroWallet_BuyEDalerCompleted;
4023 Client.BuyEDalerError += this.NeuroWallet_BuyEDalerError;
4024 Client.SellEDalerOptionsClientUrlReceived += this.NeuroWallet_SellEDalerOptionsClientUrlReceived;
4025 Client.SellEDalerOptionsCompleted += this.NeuroWallet_SellEDalerOptionsCompleted;
4026 Client.SellEDalerOptionsError += this.NeuroWallet_SellEDalerOptionsError;
4027 Client.SellEDalerClientUrlReceived += this.NeuroWallet_SellEDalerClientUrlReceived;
4028 Client.SellEDalerCompleted += this.NeuroWallet_SellEDalerCompleted;
4029 Client.SellEDalerError += this.NeuroWallet_SellEDalerError;
4032 private async Task EDalerClient_BalanceUpdated(
object? _, BalanceEventArgs e)
4034 this.lastBalance = e.Balance;
4035 this.lastEDalerEvent = DateTime.Now;
4037 BalanceEventHandler? h = this.EDalerBalanceUpdated;
4044 catch (Exception ex)
4054 public event BalanceEventHandler? EDalerBalanceUpdated;
4059 public Balance? LastEDalerBalance => this.lastBalance;
4064 public DateTime LastEDalerEvent => this.lastEDalerEvent;
4073 public bool TryParseEDalerUri(
string Uri, out
EDalerUri Parsed, out
string Reason)
4086 public async Task<string> TryDecryptMessage(
byte[] EncryptedMessage,
byte[] PublicKey, Guid TransactionId,
string RemoteEndpoint)
4092 catch (Exception ex)
4095 return string.Empty;
4114 public Task<(
AccountEvent[], bool)> GetEDalerAccountEvents(
int MaxCount)
4125 public Task<(
AccountEvent[], bool)> GetEDalerAccountEvents(
int MaxCount, DateTime From)
4134 public Task<Balance> GetEDalerBalance()
4143 public Task<(decimal, string,
PendingPayment[])> GetPendingEDalerPayments()
4157 public Task<string> CreateFullEDalerPaymentUri(
string ToBareJid, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays)
4159 this.lastEDalerEvent = DateTime.Now;
4173 public Task<string> CreateFullEDalerPaymentUri(
string ToBareJid, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays,
string Message)
4175 this.lastEDalerEvent = DateTime.Now;
4188 public Task<string> CreateFullEDalerPaymentUri(
LegalIdentity To, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays)
4190 this.lastEDalerEvent = DateTime.Now;
4204 public Task<string> CreateFullEDalerPaymentUri(
LegalIdentity To, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays,
string PrivateMessage)
4206 this.lastEDalerEvent = DateTime.Now;
4219 public string CreateIncompleteEDalerPayMeUri(
string BareJid, decimal? Amount, decimal? AmountExtra,
string Currency,
string Message)
4234 public string CreateIncompleteEDalerPayMeUri(
LegalIdentity To, decimal? Amount, decimal? AmountExtra,
string Currency,
string PrivateMessage)
4243 public async Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
4255 public async Task<OptionsTransaction> InitiateBuyEDalerGetOptions(
string ServiceId,
string ServiceProvider)
4257 string TransactionId = Guid.NewGuid().ToString();
4258 string SuccessUrl = GenerateNeuroAccessUrl(
4259 new KeyValuePair<string, object?>(
"cmd",
"beos"),
4260 new KeyValuePair<string, object?>(
"tid", TransactionId),
4265 string FailureUrl = GenerateNeuroAccessUrl(
4266 new KeyValuePair<string, object?>(
"cmd",
"beof"),
4267 new KeyValuePair<string, object?>(
"tid", TransactionId),
4272 string CancelUrl = GenerateNeuroAccessUrl(
4273 new KeyValuePair<string, object?>(
"cmd",
"beoc"),
4274 new KeyValuePair<string, object?>(
"tid", TransactionId),
4283 lock (this.currentTransactions)
4285 this.currentTransactions[TransactionId] = Result;
4291 private async Task NeuroWallet_BuyEDalerOptionsClientUrlReceived(
object? Sender, BuyEDalerClientUrlEventArgs e)
4293 lock (this.currentTransactions)
4295 if (!this.currentTransactions.ContainsKey(e.TransactionId))
4297 ServiceRef.
LogService.LogWarning(
"Client URL message for getting options for buying eDaler ignored. Transaction ID not recognized.",
4298 new KeyValuePair<string, object?>(
"TransactionId", e.TransactionId),
4299 new KeyValuePair<string, object?>(
"ClientUrl", e.ClientUrl));
4304 await Wallet.Transaction.OpenUrl(e.ClientUrl);
4307 private Task NeuroWallet_BuyEDalerOptionsCompleted(
object? _, PaymentOptionsEventArgs e)
4309 this.BuyEDalerGetOptionsCompleted(e.TransactionId, e.Options);
4310 return Task.CompletedTask;
4318 public void BuyEDalerGetOptionsCompleted(
string TransactionId, IDictionary<CaseInsensitiveString, object>[] Options)
4322 lock (this.currentTransactions)
4324 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4327 this.currentTransactions.Remove(TransactionId);
4334 private Task NeuroWallet_BuyEDalerOptionsError(
object? _, PaymentErrorEventArgs e)
4336 this.BuyEDalerGetOptionsFailed(e.TransactionId, e.Message);
4337 return Task.CompletedTask;
4345 public void BuyEDalerGetOptionsFailed(
string TransactionId,
string Message)
4349 lock (this.currentTransactions)
4351 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4354 this.currentTransactions.Remove(TransactionId);
4368 public async Task<PaymentTransaction> InitiateBuyEDaler(
string ServiceId,
string ServiceProvider, decimal Amount,
string Currency)
4370 string TransactionId = Guid.NewGuid().ToString();
4371 string SuccessUrl = GenerateNeuroAccessUrl(
4372 new KeyValuePair<string, object?>(
"cmd",
"bes"),
4373 new KeyValuePair<string, object?>(
"tid", TransactionId),
4374 new KeyValuePair<string, object?>(
"amt", Amount),
4375 new KeyValuePair<string, object?>(
"cur", Currency),
4380 string FailureUrl = GenerateNeuroAccessUrl(
4381 new KeyValuePair<string, object?>(
"cmd",
"bef"),
4382 new KeyValuePair<string, object?>(
"tid", TransactionId),
4387 string CancelUrl = GenerateNeuroAccessUrl(
4388 new KeyValuePair<string, object?>(
"cmd",
"bec"),
4389 new KeyValuePair<string, object?>(
"tid", TransactionId),
4398 lock (this.currentTransactions)
4400 this.currentTransactions[TransactionId] = Result;
4406 private static string GenerateNeuroAccessUrl(params KeyValuePair<string, object?>[] Claims)
4409 return Constants.UriSchemes.NeuroAccess +
":" +
Token;
4412 private async Task NeuroWallet_BuyEDalerClientUrlReceived(
object? Sender, BuyEDalerClientUrlEventArgs e)
4414 lock (this.currentTransactions)
4416 if (!this.currentTransactions.ContainsKey(e.TransactionId))
4418 ServiceRef.
LogService.LogWarning(
"Client URL message for buying eDaler ignored. Transaction ID not recognized.",
4419 new KeyValuePair<string, object?>(
"TransactionId", e.TransactionId),
4420 new KeyValuePair<string, object?>(
"ClientUrl", e.ClientUrl));
4425 await Wallet.Transaction.OpenUrl(e.ClientUrl);
4428 private Task NeuroWallet_BuyEDalerCompleted(
object? _, PaymentCompletedEventArgs e)
4430 this.BuyEDalerCompleted(e.TransactionId, e.Amount, e.Currency);
4431 return Task.CompletedTask;
4440 public void BuyEDalerCompleted(
string TransactionId, decimal Amount,
string Currency)
4444 lock (this.currentTransactions)
4446 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4449 this.currentTransactions.Remove(TransactionId);
4456 private Task NeuroWallet_BuyEDalerError(
object? _, PaymentErrorEventArgs e)
4458 this.BuyEDalerFailed(e.TransactionId, e.Message);
4459 return Task.CompletedTask;
4467 public void BuyEDalerFailed(
string TransactionId,
string Message)
4471 lock (this.currentTransactions)
4473 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4476 this.currentTransactions.Remove(TransactionId);
4486 public async Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
4498 public async Task<OptionsTransaction> InitiateSellEDalerGetOptions(
string ServiceId,
string ServiceProvider)
4500 string TransactionId = Guid.NewGuid().ToString();
4501 string SuccessUrl = GenerateNeuroAccessUrl(
4502 new KeyValuePair<string, object?>(
"cmd",
"seos"),
4503 new KeyValuePair<string, object?>(
"tid", TransactionId),
4508 string FailureUrl = GenerateNeuroAccessUrl(
4509 new KeyValuePair<string, object?>(
"cmd",
"seof"),
4510 new KeyValuePair<string, object?>(
"tid", TransactionId),
4515 string CancelUrl = GenerateNeuroAccessUrl(
4516 new KeyValuePair<string, object?>(
"cmd",
"seoc"),
4517 new KeyValuePair<string, object?>(
"tid", TransactionId),
4526 lock (this.currentTransactions)
4528 this.currentTransactions[TransactionId] = Result;
4534 private async Task NeuroWallet_SellEDalerOptionsClientUrlReceived(
object? Sender, SellEDalerClientUrlEventArgs e)
4536 lock (this.currentTransactions)
4538 if (!this.currentTransactions.ContainsKey(e.TransactionId))
4540 ServiceRef.
LogService.LogWarning(
"Client URL message for getting options for selling eDaler ignored. Transaction ID not recognized.",
4541 new KeyValuePair<string, object?>(
"TransactionId", e.TransactionId),
4542 new KeyValuePair<string, object?>(
"ClientUrl", e.ClientUrl));
4547 await Wallet.Transaction.OpenUrl(e.ClientUrl);
4550 private Task NeuroWallet_SellEDalerOptionsCompleted(
object? _, PaymentOptionsEventArgs e)
4552 this.SellEDalerGetOptionsCompleted(e.TransactionId, e.Options);
4553 return Task.CompletedTask;
4561 public void SellEDalerGetOptionsCompleted(
string TransactionId, IDictionary<CaseInsensitiveString, object>[] Options)
4565 lock (this.currentTransactions)
4567 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4570 this.currentTransactions.Remove(TransactionId);
4577 private Task NeuroWallet_SellEDalerOptionsError(
object? _, PaymentErrorEventArgs e)
4579 this.SellEDalerGetOptionsFailed(e.TransactionId, e.Message);
4580 return Task.CompletedTask;
4588 public void SellEDalerGetOptionsFailed(
string TransactionId,
string Message)
4592 lock (this.currentTransactions)
4594 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4597 this.currentTransactions.Remove(TransactionId);
4611 public async Task<PaymentTransaction> InitiateSellEDaler(
string ServiceId,
string ServiceProvider, decimal Amount,
string Currency)
4613 string TransactionId = Guid.NewGuid().ToString();
4614 string SuccessUrl = GenerateNeuroAccessUrl(
4615 new KeyValuePair<string, object?>(
"cmd",
"ses"),
4616 new KeyValuePair<string, object?>(
"tid", TransactionId),
4617 new KeyValuePair<string, object?>(
"amt", Amount),
4618 new KeyValuePair<string, object?>(
"cur", Currency),
4623 string FailureUrl = GenerateNeuroAccessUrl(
4624 new KeyValuePair<string, object?>(
"cmd",
"sef"),
4625 new KeyValuePair<string, object?>(
"tid", TransactionId),
4630 string CancelUrl = GenerateNeuroAccessUrl(
4631 new KeyValuePair<string, object?>(
"cmd",
"sec"),
4632 new KeyValuePair<string, object?>(
"tid", TransactionId),
4641 lock (this.currentTransactions)
4643 this.currentTransactions[TransactionId] = Result;
4649 private async Task NeuroWallet_SellEDalerClientUrlReceived(
object? Sender, SellEDalerClientUrlEventArgs e)
4651 lock (this.currentTransactions)
4653 if (!this.currentTransactions.ContainsKey(e.TransactionId))
4656 new KeyValuePair<string, object?>(
"TransactionId", e.TransactionId),
4657 new KeyValuePair<string, object?>(
"ClientUrl", e.ClientUrl));
4662 await Wallet.Transaction.OpenUrl(e.ClientUrl);
4665 private Task NeuroWallet_SellEDalerError(
object? _, PaymentErrorEventArgs e)
4667 this.SellEDalerFailed(e.TransactionId, e.Message);
4668 return Task.CompletedTask;
4676 public void SellEDalerFailed(
string TransactionId,
string Message)
4680 lock (this.currentTransactions)
4682 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4685 this.currentTransactions.Remove(TransactionId);
4691 private Task NeuroWallet_SellEDalerCompleted(
object? _, PaymentCompletedEventArgs e)
4693 this.SellEDalerCompleted(e.TransactionId, e.Amount, e.Currency);
4694 return Task.CompletedTask;
4703 public void SellEDalerCompleted(
string TransactionId, decimal Amount,
string Currency)
4707 lock (this.currentTransactions)
4709 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
4712 this.currentTransactions.Remove(TransactionId);
4721 #region Neuro-Features
4723 private DateTime lastTokenEvent = DateTime.MinValue;
4732 if (this.neuroFeaturesClient is
null)
4733 throw new InvalidOperationException(
ServiceRef.
Localizer[nameof(AppResources.NeuroFeaturesServiceNotFound)]);
4735 return this.neuroFeaturesClient;
4741 Client.TokenAdded += this.NeuroFeaturesClient_TokenAdded;
4742 Client.TokenRemoved += this.NeuroFeaturesClient_TokenRemoved;
4744 Client.StateUpdated += this.NeuroFeaturesClient_StateUpdated;
4745 Client.VariablesUpdated += this.NeuroFeaturesClient_VariablesUpdated;
4751 public DateTime LastNeuroFeatureEvent => this.lastTokenEvent;
4753 private async Task NeuroFeaturesClient_TokenRemoved(
object _,
NeuroFeatures.TokenEventArgs e)
4755 this.lastTokenEvent = DateTime.Now;
4757 NeuroFeatures.TokenEventHandler? h = this.NeuroFeatureRemoved;
4764 catch (Exception ex)
4774 public event NeuroFeatures.TokenEventHandler? NeuroFeatureRemoved;
4776 private async Task NeuroFeaturesClient_TokenAdded(
object _,
NeuroFeatures.TokenEventArgs e)
4778 this.lastTokenEvent = DateTime.Now;
4780 NeuroFeatures.TokenEventHandler? h = this.NeuroFeatureAdded;
4787 catch (Exception ex)
4797 public event NeuroFeatures.TokenEventHandler? NeuroFeatureAdded;
4799 private async Task NeuroFeaturesClient_VariablesUpdated(
object? _, VariablesUpdatedEventArgs e)
4801 VariablesUpdatedEventHandler? h = this.NeuroFeatureVariablesUpdated;
4808 catch (Exception ex)
4818 public event VariablesUpdatedEventHandler? NeuroFeatureVariablesUpdated;
4820 private async Task NeuroFeaturesClient_StateUpdated(
object? _, NewStateEventArgs e)
4822 NewStateEventHandler? h = this.NeuroFeatureStateUpdated;
4829 catch (Exception ex)
4839 public event NewStateEventHandler? NeuroFeatureStateUpdated;
4845 public Task<TokensEventArgs> GetNeuroFeatures()
4847 return this.GetNeuroFeatures(0,
int.MaxValue);
4856 public Task<TokensEventArgs> GetNeuroFeatures(
int Offset,
int MaxCount)
4865 public Task<string[]> GetNeuroFeatureReferences()
4867 return this.GetNeuroFeatureReferences(0,
int.MaxValue);
4876 public Task<string[]> GetNeuroFeatureReferences(
int Offset,
int MaxCount)
4885 public Task<TokenTotalsEventArgs> GetNeuroFeatureTotals()
4895 public Task<TokensEventArgs> GetNeuroFeaturesForContract(
string ContractId)
4907 public Task<TokensEventArgs> GetNeuroFeaturesForContract(
string ContractId,
int Offset,
int MaxCount)
4917 public Task<string[]> GetNeuroFeatureReferencesForContract(
string ContractId)
4929 public Task<string[]> GetNeuroFeatureReferencesForContract(
string ContractId,
int Offset,
int MaxCount)
4939 public Task<Token> GetNeuroFeature(
string TokenId)
4949 public Task<TokenEvent[]> GetNeuroFeatureEvents(
string TokenId)
4951 return this.GetNeuroFeatureEvents(TokenId, 0,
int.MaxValue);
4961 public Task<TokenEvent[]> GetNeuroFeatureEvents(
string TokenId,
int Offset,
int MaxCount)
4971 public Task AddNeuroFeatureTextNote(
string TokenId,
string TextNote)
4973 return this.AddNeuroFeatureTextNote(TokenId, TextNote,
false);
4984 public Task AddNeuroFeatureTextNote(
string TokenId,
string TextNote,
bool Personal)
4986 this.lastTokenEvent = DateTime.Now;
4996 public Task AddNeuroFeatureXmlNote(
string TokenId,
string XmlNote)
4998 return this.AddNeuroFeatureXmlNote(TokenId, XmlNote,
false);
5009 public Task AddNeuroFeatureXmlNote(
string TokenId,
string XmlNote,
bool Personal)
5011 this.lastTokenEvent = DateTime.Now;
5020 public Task<CreationAttributesEventArgs> GetNeuroFeatureCreationAttributes()
5029 public async Task<string> GenerateNeuroFeatureStateDiagramReport(
string TokenId)
5033 throw e.StanzaError ??
new Exception(
ServiceRef.
Localizer[nameof(AppResources.UnableToGetStateDiagram)]);
5035 return await e.ReportText.MarkdownToXaml();
5042 public async Task<string> GenerateNeuroFeatureProfilingReport(
string TokenId)
5046 throw e.StanzaError ??
new Exception(
ServiceRef.
Localizer[nameof(AppResources.UnableToGetProfiling)]);
5048 return await e.ReportText.MarkdownToXaml();
5055 public async Task<string> GenerateNeuroFeaturePresentReport(
string TokenId)
5059 throw e.StanzaError ??
new Exception(
ServiceRef.
Localizer[nameof(AppResources.UnableToGetPresent)]);
5061 return await e.ReportText.MarkdownToXaml();
5068 public async Task<string> GenerateNeuroFeatureHistoryReport(
string TokenId)
5072 throw e.StanzaError ??
new Exception(
ServiceRef.
Localizer[nameof(AppResources.UnableToGetHistory)]);
5074 return await e.ReportText.MarkdownToXaml();
5082 public Task<CurrentStateEventArgs> GetNeuroFeatureCurrentState(
string TokenId)
5098 public Task SavePrivateXml(
string Xml)
5100 return this.xmppClient?.SetPrivateXmlElementAsync(Xml)
5101 ??
throw new Exception(
"Not connected to XMPP network.");
5111 public Task SavePrivateXml(XmlElement Xml)
5113 return this.xmppClient?.SetPrivateXmlElementAsync(Xml)
5114 ??
throw new Exception(
"Not connected to XMPP network.");
5124 public async Task<XmlElement?> LoadPrivateXml(
string LocalName,
string Namespace)
5134 public Task DeletePrivateXml(
string LocalName,
string Namespace)
5136 StringBuilder Xml =
new();
5140 Xml.Append(
" xmlns='");
5143 return this.SavePrivateXml(Xml.ToString());
Contains information about a balance.
async Task< string > DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId)
Decrypts a message that was aimed at the client using the current keys.
Task<(AccountEvent[], bool)> GetAccountEventsAsync(int MaxEvents)
Gets account events associated with the wallet of the account.
const string NamespaceEDaler
Namespace of eDaler component.
Task< Balance > GetBalanceAsync()
Gets the current balance of the eDaler wallet associated with the account.
override void Dispose()
IDisposable.Dispose
string CreateIncompletePayMeUri(string BareJid, decimal? Amount, decimal? AmountExtra, string Currency, string Message)
Generates an incomplete eDaler PayMe URI.
async Task<(decimal, string, PendingPayment[])> GetPendingPayments()
Gets the amount of payments pending to be processed.
Task< string > InitiateBuyEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for buying eDaler.
Task< Transaction > SendEDalerUriAsync(string Uri)
Sends an eDaler URI to the server
Task< string > CreateFullPaymentUri(decimal Amount, decimal? AmountExtra, CaseInsensitiveString Currency, int ValidNrDays)
Creates a full payment URI to anyone who is the first in claiming the URI.
Task< IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
Gets available service providers who can help the user buy eDaler.
Task< ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
Gets available service providers who can help the user sell eDaler.
Task< string > InitiateGetOptionsSellEDalerAsync(string ServiceId, string ServiceProvider)
Initiates a process for getting payment options for selling eDaler.
Task< string > InitiateGetOptionsBuyEDalerAsync(string ServiceId, string ServiceProvider)
Initiates a process for getting payment options for buying eDaler.
Task< string > InitiateSellEDalerAsync(string ServiceId, string ServiceProvider, decimal Amount, string Currency)
Initiates a process for selling eDaler.
Contains information about a pending payment.
Represents a transaction in the eDaler network.
Abstract base class for eDaler URIs
static bool TryParse(string Uri, out EDalerUri Result)
Tries to parse an eDaler URI
The Application class, representing an instance of the Neuro-Access app.
static Task SetRegistrationPageAsync()
Switches the application to the on-boarding experience.
static Task< bool > OpenUrlAsync(string Url)
Opens an URL in the application.
static new? App Current
Gets the current application, type casted to App.
const int DeviceBatchSize
Number of devices to load in a single batch.
Machine-readable names in contracts.
const string PaymentInstructionsNamespace
Namespace for payment instructions
const string BuyEDaler
Local name for contracts for buying eDaler.
const string SellEDaler
Local name for contracts for selling eDaler.
const string OnboardingDomain
Neuro-Access onboarding domain.
static readonly TimeSpan Reconnect
Reconnect interval
const string Default
The default language code.
Absolute paths to important pages.
const string RegistrationPage
Path to registration page.
const int DefaultImageHeight
The default height to use when generating QR Code images.
const int DefaultImageWidth
The default width to use when generating QR Code images.
Runtime setting key names.
const string TransferIdCodeSent
Transfer ID code
static readonly TimeSpan XmppConnect
XMPP Connect timeout
static readonly TimeSpan UploadFile
Upload file timeout
XMPP Protocol Properties.
const string Partition
Partition
const string SourceId
Source ID
const string NodeId
Node ID
const string Jid
Jabber ID
A set of never changing property constants and helpful values.
Contains a local reference to a contract that the user has created or signed.
async Task SetContract(Contract Contract)
Sets a parsed contract.
Represent an attachment to a LegalIdentity.
bool IsUnloading
Gets whether the service is being unloaded.
bool BeginLoad(bool IsResuming, CancellationToken CancellationToken)
Sets the IsLoading flag if the service isn't already loading.
void EndLoad(bool isLoaded)
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
bool IsResuming
If App is resuming service.
bool BeginUnload()
Sets the IsLoading flag if the service isn't already unloading.
void EndUnload()
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
bool IsLoaded
Gets whether the service is loaded.
Contains information about a request to read a thing.
Contains information about a request to read a thing.
Contains information about a request to become "friends", i.e. subscribe to presence.
Contains information about an incoming chat message.
Base class that references services in the app.
static ILogService LogService
Log service.
static INetworkService NetworkService
Network service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static IPushNotificationService PushNotificationService
Service for managing push notifications from the network.
static INotificationService NotificationService
Service for managing notifications for the user.
static ITagProfile TagProfile
TAG Profile service.
static ICryptoService CryptoService
Crypto service.
static IStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
DateTime Created
When message was created
string Html
HTML of message
string PlainText
Plain text of message
string Markdown
Markdown of message
A page that displays a list of the current user's contacts.
The view model to bind to when displaying the list of contacts.
async Task MessageAddedAsync(ChatMessage Message)
External message has been received
async Task MessageUpdatedAsync(ChatMessage Message)
External message has been updated
The data model for registering an identity.
Property[] ToProperties(IXmppService XmppService)
Converts the RegisterIdentityModel to an array of .
Event raised when a token has been created.
async Task< ReportEventArgs > GenerateHistoryReportAsync(string TokenId, ReportFormat Format)
Generates a history report of a state-machine belonging to a token.
Task< TokensEventArgs > GetTokensAsync()
Get tokens the account owns.
Task< TokensEventArgs > GetContractTokensAsync(string ContractId)
Get tokens created by a contract the account has access to.
Task< string[]> GetContractTokenReferencesAsync(string ContractId)
Get references to tokens created by a contract the account has access to.
override void Dispose()
IDisposable.Dispose
async Task< ReportEventArgs > GeneratePresentReportAsync(string TokenId, ReportFormat Format)
Generates a present report of a state-machine belonging to a token.
async Task< CurrentStateEventArgs > GetCurrentStateAsync(string TokenId)
Gets the current state of a state-machine belonging to a token.
async Task< CreationAttributesEventArgs > GetCreationAttributesAsync()
Gets attributes relevant for creating tokens on the broker.
async Task< ReportEventArgs > GenerateProfilingReportAsync(string TokenId, ReportFormat Format)
Generates a profiling report of a state-machine belonging to a token.
Task AddTextNoteAsync(string TokenId, string Note)
Adds a text note to a token. Notes attached to a token can be retrieved by calling GetEvents.
const string NamespaceNeuroFeatures
Namespace for Neuro-Features.
Task< TokenTotalsEventArgs > GetTotalsAsync()
Get totals of tokens the sender owns.
Task< string[]> GetTokenReferencesAsync()
Get references to tokens the account owns.
Task< TokenEvent[]> GetEventsAsync(string TokenId)
Get events registered for a token the account owns.
async Task< ReportEventArgs > GenerateStateDiagramAsync(string TokenId, ReportFormat Format)
Generates a state diagram of a state-machine belonging to a token.
async Task< Token > GetTokenAsync(string TokenId)
Gets a token, given its full ID.
Task AddXmlNoteAsync(string TokenId, string Note)
Adds a xml note to a token. Notes attached to a token can be retrieved by calling GetEvents.
Helps with parsing of commong data types.
static readonly char[] CRLF
Contains the CR LF character sequence.
static string GetBody(string Html)
Extracts the contents of the BODY element in a HTML string.
Static class managing encoding and decoding of internet content.
static Task< object > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Helps with common JSON-related tasks.
static readonly DateTime UnixEpoch
Unix Date and Time epoch, starting at 1970-01-01T00:00:00Z
Contains a markdown document. This markdown document class supports original markdown,...
async Task< string > GeneratePlainText()
Generates Plain Text from the markdown text.
async Task< string > GenerateHTML()
Generates HTML from the markdown text.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static string Encode(string s)
Encodes a string for use in XML.
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Class representing an event.
Filters incoming events and passes remaining events to a secondary event sink.
IEventSink SecondarySink
Secondary event sink receiving the events passing the filter.
Static class managing the application event log. Applications and services log events on this static ...
static void Register(IEventSink EventSink)
Registers an event sink with the event log. Call Unregister(IEventSink) to unregister it,...
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
static bool Unregister(IEventSink EventSink)
Unregisters an event sink from the event log.
static void Alert(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an alert event.
virtual void Dispose()
IDisposable.Dispose()
Event sink sending events to a destination over the XMPP network.
const string NamespaceEventLogging
urn:xmpp:eventlog
Sniffer that stores events in memory.
Class implementing blocking (XEP-0191) and spam reporting (XEP-0377).
override void Dispose()
IDisposable.Dispose
async Task BlockJID(string JID, ReportingReason Reason, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Blocks a JID
Implements an XMPP concentrator client interface.
override void Dispose()
Disposes of the extension.
Implements an XMPP concentrator server interface.
const string NamespaceConcentratorCurrent
Neuro-Foundation v1 namespace
Static class managing editable parameters in objects. Editable parameters are defined by using the at...
Contains a reference to an attachment assigned to a legal object.
string FileName
Filename of attachment.
string ContentType
Internet Content Type of binary attachment.
Contains the definition of a contract
string ForMachinesLocalName
Local name used by the root node of the machine-readable contents of the contract (ForMachines).
string ContractId
Contract identity
string ForMachinesNamespace
Namespace used by the root node of the machine-readable contents of the contract (ForMachines).
Adds support for legal identities, smart contracts and signatures to an XMPP client.
Task< bool > ImportKeys(string Xml)
Imports keys
EndpointSecurity LocalE2eEndpoint
Endpoint used for End-to-End encryption.
async Task GenerateNewKeys()
Generates new keys for the contracts clients.
Task< LegalIdentity > ApplyAsync(Property[] Properties)
Applies for a legal identity to be registered.
Task SelectPeerReviewServiceAsync(string Provider, string ServiceId)
Selects a service provider for peer review. This needs to be done before requesting the trust provide...
Task PetitionIdentityResponseAsync(string LegalId, string PetitionId, string RequestorFullJid, bool Response)
Sends a response to a petition for information about a legal identity. When a petition is received,...
bool? ValidateSignature(LegalIdentity Identity, byte[] Data, byte[] Signature)
Validates a signature of binary data.
Task< KeyValuePair< string, TemporaryFile > > GetAttachmentAsync(string Url, SignWith SignWith)
Gets an attachment from a Trust Provider
Task< LegalIdentity > ObsoleteLegalIdentityAsync(string LegalIdentityId)
Obsoletes one of the legal identities of the account, given its ID.
Task SendContractProposal(Contract Contract, string Role, string To)
Sends a contract proposal to a recipient. If the contract contains encrypted parameters,...
Task< ServiceProviderWithLegalId[]> GetPeerReviewIdServiceProvidersAsync()
Gets available service providers who can help review an ID application.
Task PetitionIdentityAsync(string LegalId, string PetitionId, string Purpose)
Sends a petition to the owner of a legal identity, to access the information in the identity....
async Task< IdApplicationAttributesEventArgs > GetIdApplicationAttributesAsync()
Gets attributes relevant for application for legal identities on the broker.
Task< bool > LoadKeys(bool CreateIfNone)
Loads keys from the underlying persistence layer.
Task< LegalIdentity > GetLegalIdentityAsync(string LegalIdentityId)
Gets legal identity registered with the account.
Task AuthorizeAccessToIdAsync(string LegalId, string RemoteId, bool Authorized)
Authorizes access to (or revokes access to) a Legal ID of the caller.
Task PetitionSignatureResponseAsync(string LegalId, byte[] Content, byte[] Signature, string PetitionId, string RequestorFullJid, bool Response)
Sends a response to a petition for a signature by the client. When a petition is received,...
Task< bool > HasPrivateKey(LegalIdentity Identity)
Checks if the private key of a legal identity is available. Private keys are required to be able to s...
Task< IdentityStatus > ValidateAsync(LegalIdentity Identity)
Validates a legal identity.
Task PetitionContractAsync(string ContractId, string PetitionId, string Purpose)
Sends a petition to the parts of a smart contract, to access the information in the contract....
async Task< LegalIdentity > AddLegalIdAttachmentAsync(string LegalId, string GetUrl, byte[] Signature)
Adds an attachment to a newly created legal identity.
Task< LegalIdentity > CompromisedLegalIdentityAsync(string LegalIdentityId)
Reports as Compromised one of the legal identities of the account, given its ID.
Task< Contract > GetContractAsync(string ContractId)
Gets a contract
Task< byte[]> SignAsync(byte[] Data, SignWith SignWith)
Signs binary data with the corresponding private key.
const string NamespaceOnboarding
http://waher.se/schema/Onboarding/v1.xsd
Task PetitionContractResponseAsync(string ContractId, string PetitionId, string RequestorFullJid, bool Response)
Sends a response to a petition to access a smart contract. When a petition for a contract is received...
Task ReadyForApprovalAsync(string LegalIdentityId)
Marks an Identity as Ready for Approval. Call this after necessary attachments have been added....
async Task< LegalIdentity > AddPeerReviewIDAttachment(LegalIdentity Identity, LegalIdentity ReviewerLegalIdentity, byte[] PeerSignature)
Adds an attachment to a legal identity with information about a peer review of the identity.
Task< LegalIdentity[]> GetLegalIdentitiesAsync()
Gets legal identities registered with the account.
async Task< string > ExportKeys()
Exports Keys to XML.
Task< Contract > SignContractAsync(Contract Contract, string Role, bool Transferable)
Signs a contract
override void Dispose()
Disposes of the extension.
Task< string[]> GetSignedContractReferencesAsync()
Get references to contracts the account has signed.
Task EnableE2eEncryption(bool UseLocalKeys)
Defines if End-to-End encryption should use the keys used by the contracts client to perform signatur...
Task PetitionPeerReviewIDAsync(string LegalId, LegalIdentity Identity, string PetitionId, string Purpose)
Sends a petition to a third party to peer review a new legal identity. The petition is not guaranteed...
Task< Contract > CreateContractAsync(XmlElement ForMachines, HumanReadableText[] ForHumans, Role[] Roles, Part[] Parts, Parameter[] Parameters, ContractVisibility Visibility, ContractParts PartsMode, Duration? Duration, Duration? ArchiveRequired, Duration? ArchiveOptional, DateTime? SignAfter, DateTime? SignBefore, bool CanActAsTemplate)
Creates a new contract.
Task< Contract > DeleteContractAsync(string ContractId)
Deletes a contract
Task< string[]> GetCreatedContractReferencesAsync()
Get references to contracts the account has created.
Task< Contract > ObsoleteContractAsync(string ContractId)
Obsoletes a contract
static readonly string[] NamespacesLegalIdentities
Namespaces supported for legal identities.
const string NamespaceLegalIdentitiesCurrent
Current namespace for legal identities.
DateTime Created
When the identity object was created
string Id
ID of the legal identity
void Serialize(StringBuilder Xml, bool IncludeNamespace, bool IncludeIdAttribute, bool IncludeClientSignature, bool IncludeAttachments, bool IncludeStatus, bool IncludeServerSignature, bool IncludeAttachmentReferences)
Serializes the identity to XML
static LegalIdentity Parse(XmlElement Xml)
Parses an identity from its XML representation
Attachment[] Attachments
Attachments assigned to the legal identity.
Abstract base class for contractual parameters
Class defining a part in a contract
Contains information about a service provider.
Abstract base class of signatures
Implements an XMPP control client interface.
Task GetForm(string To, string Language, params ThingReference[] Nodes)
Gets a control form.
bool Ok
If the response is an OK result response (true), or an error response (false).
string ErrorText
Any error specific text.
Task< string > GetJwtTokenAsync(int Seconds)
Gets a JWT token from the server to which the client is connceted. The JWT token encodes the current ...
Class managing HTTP File uploads, as defined in XEP-0363.
static ? long FindMaxFileSize(XmppClient Client, ServiceDiscoveryEventArgs e)
Finds the maximum file size supported by the file upload service.
bool HasSupport
If support has been found.
const string Namespace
urn:xmpp:http:upload:0
Event arguments for HTTP File Upload callback methods.
async Task PUT(byte[] Content, string ContentType, int Timeout)
Uploads file content to the server.
Client managing the Personal Eventing Protocol (XEP-0163). https://xmpp.org/extensions/xep-0163....
void RegisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Registers an event handler of a specific type of personal events.
override void Dispose()
Disposes of the extension.
bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Unregisters an event handler of a specific type of personal events.
Implements an XMPP provisioning client interface.
Task CanControlResponseDevice(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a device token.
Task GetDevices(int Offset, int MaxCount, EventHandlerAsync< SearchResultEventArgs > Callback, object State)
Gets devices owned by the caller.
Task CanReadResponseService(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a service token.
Task CanReadResponseUser(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a user token.
Task CanReadResponseAll(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, for all future requests.
static readonly string[] NamespacesProvisioningDevice
Namespaces supported for provisioning devices.
Task CanControlResponseCaller(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on the JID of the caller.
static readonly string[] NamespacesProvisioningOwner
Namespaces supported for provisioning owners.
Task CanControlResponseService(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a service token.
Task DeleteDeviceRules()
Deletes te device rules of all owned devices.
string ProvisioningServerAddress
Provisioning server XMPP address.
Task CanReadResponseCaller(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on the JID of the caller.
Task CanReadResponseDomain(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on the domain of the caller.
override void Dispose()
Disposes of the extension.
Task CanControlResponseUser(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on a user token.
Task CanControlResponseDomain(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, based on the domain of the caller.
Task CanReadResponseDevice(string JID, string RemoteJID, string Key, bool CanRead, FieldType FieldTypes, string[] FieldNames, string Token, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Read" question, based on a device token.
Task CanControlResponseAll(string JID, string RemoteJID, string Key, bool CanControl, string[] ParameterNames, IThingReference Node, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Can Control" question, for all future requests.
Task GetCertificate(string Token, EventHandlerAsync< CertificateEventArgs > Callback, object State)
Gets the certificate the corresponds to a token. This certificate can be used to identify services,...
Task IsFriendResponse(string JID, string RemoteJID, string Key, bool IsFriend, RuleRange Range, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends a response to a previous "Is Friend" question.
static readonly string[] NamespacesProvisioningToken
Namespaces supported for provisioning tokens.
Filters things with a named numeric-valued tag equal to a given value.
Abstract base class for all search operators.
Filters things with a named string-valued tag equal to a given value.
Contains information about a thing in a search result.
Implements an XMPP thing registry client interface.
static bool TryDecodeIoTDiscoURI(string DiscoUri, out IEnumerable< SearchOperator > Operators)
Decodes an IoTDisco URI.
static bool TryDecodeIoTDiscoClaimURI(string DiscoUri, out MetaDataTag[] Tags)
Tries to decode an IoTDisco Claim URI (subset of all possible IoTDisco URIs).
static bool IsIoTDiscoDirectURI(string DiscoUri)
Checks if a URI is a direct reference URI.
static bool IsIoTDiscoClaimURI(string DiscoUri)
Checks if a URI is a claim URI.
override void Dispose()
Disposes of the extension.
Task Disown(string ThingJid, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Disowns a thing, so that it can be claimed by another.
string ThingRegistryAddress
Thing Registry XMPP address.
static bool IsIoTDiscoSearchURI(string DiscoUri)
Checks if a URI is a search URI.
Task Mine(MetaDataTag[] MetaDataTags, EventHandlerAsync< NodeResultEventArgs > Callback, object State)
Claims a thing.
static readonly string[] NamespacesDiscovery
Namespaces supported for discovery.
Task Search(int Offset, int MaxCount, SearchOperator[] SearchOperators, EventHandlerAsync< SearchResultEventArgs > Callback, object State)
Searches for publically available things in the thing registry.
Client managing communication with a Publish/Subscribe component. https://xmpp.org/extensions/xep-006...
const string NamespaceDelayedDelivery
urn:xmpp:delay (XEP-0203)
async Task NewTokenAsync(string Token, PushMessagingService Service, ClientType ClientType)
Reports a new push token to the server.
const string MessagePushNamespace
http://waher.se/Schema/PushNotification.xsd
async Task AddRuleAsync(MessageType MessageType, string LocalName, string Namespace, string Channel, string MessageVariable, string PatternMatchingScript, string ContentScript)
Adds a push notification rule to the client account.
override void Dispose()
Disposes of the extension.
async Task ClearRulesAsync()
Clears available push notification rules for the client.
Class redirecting sniffer output to a remote client.
override Task Information(DateTime Timestamp, string Comment)
Called to inform the viewer of something.
override Task ReceiveText(DateTime Timestamp, string Text)
Called when text has been received.
override Task TransmitText(DateTime Timestamp, string Text)
Called when text has been transmitted.
override Task Error(DateTime Timestamp, string Error)
Called to inform the viewer of an error state.
override Task Warning(DateTime Timestamp, string Warning)
Called to inform the viewer of a warning state.
Maintains information about an item in the roster.
Implements an XMPP sensor client interface.
Task< SensorDataClientRequest > RequestReadout(string Destination, FieldType Types)
Requests a sensor data readout.
override void Dispose()
Disposes of the extension.
Manages a sensor data client request.
Contains information about an identity of an entity.
Contains information about an item of an entity.
Event arguments for service discovery responses.
bool HasFeature(string Feature)
Checks if the remote entity supports a specific feature.
bool HasAnyFeature(params string[] Features)
Checks if the remote entity supports any of a set of features.
Event arguments for service items discovery responses.
Access cannot be granted because an existing resource exists with the same name or address; the assoc...
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Task RequestRevokePresenceSubscription(string BareJid)
Requests a previous presence subscription request revoked.
Task ChangePassword(string NewPassword)
Changes the password of the current user.
Task< ServiceItemsDiscoveryEventArgs > ServiceItemsDiscoveryAsync(string To)
Performs an asynchronous service items discovery request
XmppState State
Current state of connection.
Task RemoveRosterItem(string BareJID)
Removes an item from the roster.
async void Dispose()
Closes the connection and disposes of all resources.
Task< ServiceDiscoveryEventArgs > ServiceDiscoveryAsync(string To)
Performs an asynchronous service discovery request
Task RequestPresenceSubscription(string BareJid)
Requests subscription of presence information from a contact.
async Task< XmlElement > GetPrivateXmlElementAsync(string LocalName, string Namespace)
Gets an XML element from the Private XML Storage for the current account.
Task AddRosterItem(RosterItem Item)
Adds an item to the roster. If an item with the same Bare JID is found in the roster,...
async Task< XmlElement > IqSetAsync(string To, string Xml)
Performs an asynchronous IQ Set request/response operation.
Task RequestPresenceUnsubscription(string BareJid)
Requests unssubscription of presence information from a contact.
Task SendServiceDiscoveryRequest(string To, EventHandlerAsync< ServiceDiscoveryEventArgs > Callback, object State)
Sends a service discovery request
const string NamespaceQuickLogin
http://waher.se/Schema/QL.xsd
Task Connect()
Connects the client.
async Task SetPresenceAsync(Availability Availability, params KeyValuePair< string, string >[] Status)
Sets the presence of the connection. Add a CustomPresenceXml event handler to add custom presence XML...
void AllowRegistration()
If registration of a new account is allowed. Requires a password. Having a password hash is not suffi...
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Class containing credentials for an XMPP client connection.
const int DefaultPort
Default XMPP Server port.
virtual void Dispose()
Disposes of the extension.
XmppClient Client
XMPP Client.
Represents a case-insensitive string.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IEnumerable< object > > FindDelete(string Collection, params string[] SortOrder)
Finds objects in a given collection and deletes them in the same atomic operation.
static IDatabaseProvider Provider
Registered database provider.
static async Task Update(object Object)
Updates an object in the database.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
Static interface for ledger persistence. In order to work, a ledger provider has to be assigned to it...
static void Register(ILedgerProvider LedgerProvider)
Registers a ledger provider for use from the static Ledger class, throughout the lifetime of the appl...
static bool HasProvider
If a ledger provider is registered.
static void StartListeningToDatabaseEvents()
Makes the ledger listen on database events. Each call to StartListeningToDatabaseEvents must be follo...
Simple ledger that records anything that happens in the database to XML files in the program data fol...
Task Start()
Called when processing starts.
Static class that dynamically manages types and interfaces available in the runtime environment.
static void SetModuleParameter(string Name, object Value)
Sets a module parameter. This parameter value will be accessible to modules when they are loaded.
Static class managing persistent settings.
static async Task< string > GetAsync(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Static class containing predefined JWT claim names.
const string Issuer
Issuer of the JWT
const string Subject
Subject of the JWT (the user)
const string ClientId
Client identifier
const string ExpirationTime
Time after which the JWT expires
Contains a reference to a thing
Task CheckPushNotificationToken(TokenInformation? TokenInformation=null)
Checks if the Push Notification Token is current and registered properly.
The TAG Profile is the heart of the digital identity for a specific user/device. Use this instance to...
string? NeuroFeaturesJid
The XMPP server's Neuro-Features service JID.
bool IsCompleteOrWaitingForValidation()
Returns true if the registration process for this ITagProfile is either fully complete or is just awa...
string? HttpFileUploadJid
The XMPP server's file upload Jid.
Task SetLegalIdentity(LegalIdentity? Identity, bool RemoveOldAttachments)
Sets the legal identity of the profile.
void GoToStep(RegistrationStep NewStep, bool SupressEvent=false)
Changes the current onboarding step.
long HttpFileUploadMaxSize
The XMPP server's max size for file uploads.
string? Account
The account name for this profile
void SetDomain(string DomainName, bool DefaultXmppConnectivity, string Key, string Secret)
Set the domain name to connect to.
string? RegistryJid
The Thing Registry JID
string? EDalerJid
The XMPP server's eDaler service JID.
Task SetIdentityApplication(LegalIdentity? Identity, bool RemoveOldAttachments)
Sets the legal identity of the profile.
bool ShouldCreateClient()
Returns true if the registration process for this ITagProfile has an account but not a legal id,...
LegalIdentity? IdentityApplication
Any current Identity application.
string? LogJid
The XMPP server's log Jid.
string? ApiKey
API Key, for creating new account.
string? LegalJid
The Jabber Legal JID for this user/profile.
string? ApiSecret
API Secret, for creating new account.
bool DefaultXmppConnectivity
If connecting to the domain can be done using default parameters (host=domain, default c2s port).
bool SupportsPushNotification
If Push Notification is supported by server.
string? XmppPasswordHash
A hash of the current XMPP password.
Task ClearLegalIdentity()
Revert the Set LegalIdentity
void SetFileUploadParameters(string httpFileUploadJid, long maxSize)
Used during XMPP service discovery. Sets the file upload parameters.
void CheckContractReference(ContractReference Reference)
Checks if Tag Profile properties need to be changed, with regards to a current ContractReference obje...
void ClearAll()
Clears the entire profile.
string? XmppPasswordHashMethod
The hash method used for hashing the XMPP password.
string? ProvisioningJid
The XMPP server's provisioning Jid.
LegalIdentity? LegalIdentity
The legal identity of the current user/profile.
bool NeedsUpdating()
Returns true if the current ITagProfile needs to have its values updated, false otherwise.
void SetAccount(string AccountName, string ClientPasswordHash, string ClientPasswordHashMethod)
Set the account name and password for a new account.
string? Domain
The domain this profile is connected to.
string BareJid
The Bare Jid of the current connection, or null.
Task< HttpFileUploadEventArgs > RequestUploadSlotAsync(string FileName, string ContentType, long ContentSize)
Uploads a file to the upload component.
Task Flush()
Persists any pending changes.
Interface for thing references.
RegistrationStep
The different steps of a TAG Profile registration journey.
class OptionsTransaction(string TransactionId)
Maintains the status of an ongoing retrieval of payment options.
class PaymentTransaction(string TransactionId, string Currency)
Maintains the status of an ongoing payment transaction.
ReportFormat
Desired report format
Action
The Action field indicates the action performed by the Reporting-MTA as a result of its attempt to de...
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
ReportingReason
Reason for blocking.
SignWith
Options on what keys to use when signing data.
ContractParts
How the parts of the contract are defined.
ContractVisibility
Visibility types for contracts.
IdentityStatus
Validation Status of legal identity
RuleRange
Range of a rule change
ClientType
Type of client requesting notification.
PushMessagingService
Push messaging service used.
Availability
Resource availability.
QoSLevel
Quality of Service Level for asynchronous messages. Support for QoS Levels must be supported by the r...
SubscriptionState
State of a presence subscription.
MessageType
Type of message received.
XmppState
State of XMPP connection.
E2ETransmission
End-to-end encryption mode.
Reason
Reason a token is not valid.
ReportType
Type of report to generate
FieldType
Field Type flags
Represents a duration value, as defined by the xsd:duration data type: http://www....