2#define DEBUG_XMPP_LOCAL
8using System.ComponentModel;
9using System.Diagnostics;
10using System.Diagnostics.CodeAnalysis;
11using System.Globalization;
14using System.Reflection;
15using System.Runtime.CompilerServices;
18using CommunityToolkit.Mvvm.Messaging;
116 private Timer? reconnectTimer;
117 private Timer? updatePasswordTimer;
118 private string? domainName;
119 private string? accountName;
120 private string? passwordHash;
121 private string? passwordHashMethod;
122 private bool xmppConnected =
false;
123 private DateTime xmppLastStateChange = DateTime.MinValue;
124 private readonly
InMemorySniffer? sniffer =
new(250,
"Connection In-memory sniffer.");
125 private bool isCreatingClient;
127 private string? token =
null;
128 private DateTime tokenCreated = DateTime.MinValue;
129#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE || DEBUG_NFC_REMOTE
130 private const string debugRecipient =
"";
132#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE || DEBUG_NFC_REMOTE
139 #region Creation / Destruction
145 private async Task CreateXmppClient()
147 if (this.isCreatingClient)
152 this.isCreatingClient =
true;
154 if (!this.XmppParametersCurrent() || this.XmppStale())
156 if (this.xmppClient is not
null)
157 await this.DestroyXmppClient();
170 HostName = this.domainName;
185 this.xmppLastStateChange = DateTime.Now;
186 this.xmppConnected =
false;
188 Assembly AppAssembly =
App.
Current!.GetType().Assembly;
190 if (
string.IsNullOrEmpty(this.passwordHashMethod))
192 this.xmppClient =
new XmppClient(HostName, PortNumber, this.accountName, this.passwordHash,
197 this.xmppClient =
new XmppClient(HostName, PortNumber, this.accountName, this.passwordHash, this.passwordHashMethod,
202 this.xmppClient.Add(LocalSniffer);
205#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE
206 if (!
string.IsNullOrEmpty(debugRecipient))
209#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE || DEBUG_NFC_REMOTE
210 this.debugSniffer =
new RemoteSniffer(debugRecipient, DateTime.MaxValue,
this.xmppClient,
this.xmppClient,
214 this.xmppClient.Add(this.debugSniffer);
217 if (this.debugEventSink is not
null)
220 this.debugEventSink?.
Dispose();
221 this.debugEventSink =
null;
224 this.debugEventSink =
new EventFilter(
"Debug Event Filter",
225 new XmppEventSink(
"Debug Event Sink", this.xmppClient, debugRecipient,
false),
228 if (this.xmppClient is null || this.xmppClient.State != XmppState.Connected)
231 return string.IsNullOrEmpty(Event.StackTrace) || !Event.StackTrace.Contains(
"XmppEventSink");
239 XmlFileLedger XmlFileLedger =
new(
new RemoteLedgerWriter());
242 await XmlFileLedger.Start();
247#if DEBUG_XMPP_REMOTE || DEBUG_LOG_REMOTE || DEBUG_DB_REMOTE
250 this.xmppClient.DefaultRetryTimeout = 30000;
251 this.xmppClient.DefaultNrRetries = 0;
252 this.xmppClient.RequestRosterOnStartup =
false;
253 this.xmppClient.TrustServer = !IsIpAddress;
254 this.xmppClient.AllowCramMD5 =
false;
255 this.xmppClient.AllowDigestMD5 =
false;
256 this.xmppClient.AllowPlain =
false;
257 this.xmppClient.AllowEncryption =
true;
258 this.xmppClient.AllowScramSHA1 =
true;
259 this.xmppClient.AllowScramSHA256 =
true;
260 this.xmppClient.AllowQuickLogin =
true;
262 this.xmppClient.RequestRosterOnStartup =
true;
263 this.xmppClient.OnStateChanged += this.XmppClient_StateChanged;
264 this.xmppClient.OnConnectionError += this.XmppClient_ConnectionError;
265 this.xmppClient.OnError += this.XmppClient_Error;
266 this.xmppClient.OnChatMessage += this.XmppClient_OnChatMessage;
267 this.xmppClient.OnNormalMessage += this.XmppClient_OnNormalMessage;
268 this.xmppClient.OnPresenceSubscribe += this.XmppClient_OnPresenceSubscribe;
269 this.xmppClient.OnPresenceUnsubscribed += this.XmppClient_OnPresenceUnsubscribed;
270 this.xmppClient.OnRosterItemAdded += this.XmppClient_OnRosterItemAdded;
271 this.xmppClient.OnRosterItemUpdated += this.XmppClient_OnRosterItemUpdated;
272 this.xmppClient.OnRosterItemRemoved += this.XmppClient_OnRosterItemRemoved;
273 this.xmppClient.OnPresence += this.XmppClient_OnPresence;
277 this.xmppFilteredEventSink =
new EventFilter(
"XMPP Event Filter",
283 this.abuseClient =
new AbuseClient(this.xmppClient);
288 this.RegisterContractsEventHandlers();
290 await this.contractsClient.
LoadKeys(
false);
303 ManagePresenceSubscriptionRequests =
false
306 this.provisioningClient.CanControlQuestion += this.ProvisioningClient_CanControlQuestion;
307 this.provisioningClient.CanReadQuestion += this.ProvisioningClient_CanReadQuestion;
308 this.provisioningClient.IsFriendQuestion += this.ProvisioningClient_IsFriendQuestion;
314 this.RegisterEDalerEventHandlers(this.eDalerClient);
320 this.RegisterNeuroFeatureEventHandlers(this.neuroFeaturesClient);
331 this.pepClient =
new PepClient(this.xmppClient);
334 this.ReregisterPepEventHandlers(this.pepClient);
336 this.httpxClient =
new HttpxClient(this.xmppClient, 8192);
342 this.IsLoggedOut =
false;
343 await this.xmppClient.Connect(IsIpAddress ?
string.Empty : this.domainName);
344 this.RecreateReconnectTimer();
352 new KeyValuePair<string, object?>(
"Domain", this.domainName ??
string.Empty),
353 new KeyValuePair<string, object?>(
"Account", this.accountName ??
string.Empty),
361 this.isCreatingClient =
false;
366 private class RemoteLedgerWriter()
367 : TextWriter(CultureInfo.CurrentCulture)
369 private readonly StringBuilder sb =
new();
371 public override Encoding Encoding => Encoding.Unicode;
372 public override void Flush() => this.FlushAsync().Wait();
373 public override Task FlushAsync(CancellationToken cancellationToken) => this.FlushAsync();
375 public override async Task FlushAsync()
379 string s = this.sb.ToString();
380 string s2 = s.TrimStart();
381 if (
string.IsNullOrEmpty(s2))
393 int i = s2.IndexOf(
'<');
397 string[] Rows = s.Replace(
"\r\n",
"\n").Replace(
'\r',
'\n').Split(
'\n');
399 if (s2.StartsWith(
"<New", StringComparison.OrdinalIgnoreCase))
401 foreach (
string Row
in Rows)
404 else if (s2.StartsWith(
"<Update", StringComparison.OrdinalIgnoreCase))
406 foreach (
string Row
in Rows)
409 else if (s2.StartsWith(
"<Delete", StringComparison.OrdinalIgnoreCase))
411 foreach (
string Row
in Rows)
412 await Sniffer.
Error(Row);
414 else if (s2.StartsWith(
"<Clear", StringComparison.OrdinalIgnoreCase))
416 foreach (
string Row
in Rows)
421 foreach (
string Row
in Rows)
431 public override void Write(
char value) => this.sb.Append(value);
432 public override void Write(
char[]? buffer) => this.sb.Append(buffer);
433 public override void Write(
char[] buffer,
int index,
int count) => this.sb.Append(
new string(buffer, index, count));
434 public override void Write(ReadOnlySpan<char> buffer) => this.sb.Append(
new string(buffer));
435 public override void Write(
bool value) => this.sb.Append(value);
436 public override void Write(
int value) => this.sb.Append(value);
437 public override void Write(uint value) => this.sb.Append(value);
438 public override void Write(
long value) => this.sb.Append(value);
439 public override void Write(ulong value) => this.sb.Append(value);
440 public override void Write(
float value) => this.sb.Append(value);
441 public override void Write(
double value) => this.sb.Append(value);
442 public override void Write(decimal value) => this.sb.Append(value);
443 public override void Write(
string? value) => this.sb.Append(value);
444 public override void Write(
object? value) => this.sb.Append(value);
445 public override void Write(StringBuilder? value) => this.sb.Append(value);
446 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0) => this.sb.Append(
string.Format(this.FormatProvider, format, arg0));
447 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1) => this.sb.Append(
string.Format(this.FormatProvider, format, arg0, arg1));
448 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));
449 public override void Write([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format, params
object?[] arg) => this.sb.Append(
string.Format(this.FormatProvider, format, arg));
450 public override Task WriteAsync(
char value) { this.sb.Append(value);
return Task.CompletedTask; }
451 public override Task WriteAsync(
string? value) { this.sb.Append(value);
return Task.CompletedTask; }
452 public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken =
default) { this.sb.Append(value);
return Task.CompletedTask; }
453 public override Task WriteAsync(
char[] buffer,
int index,
int count) { this.sb.Append(
new string(buffer, index, count));
return Task.CompletedTask; }
454 public override Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken =
default) { this.sb.Append(buffer);
return Task.CompletedTask; }
455 public override void WriteLine() => this.sb.AppendLine(
string.Empty);
456 public override void WriteLine(
char value) => this.sb.AppendLine(value.ToString());
457 public override void WriteLine(
char[]? buffer) => this.sb.AppendLine(
new string(buffer));
458 public override void WriteLine(
char[] buffer,
int index,
int count) => this.sb.AppendLine(
new string(buffer, index, count));
459 public override void WriteLine(ReadOnlySpan<char> buffer) => this.sb.AppendLine(
new string(buffer));
460 public override void WriteLine(
bool value) => this.sb.AppendLine(value.ToString());
461 public override void WriteLine(
int value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
462 public override void WriteLine(uint value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
463 public override void WriteLine(
long value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
464 public override void WriteLine(ulong value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
465 public override void WriteLine(
float value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
466 public override void WriteLine(
double value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
467 public override void WriteLine(decimal value) => this.sb.AppendLine(value.ToString(CultureInfo.CurrentCulture));
468 public override void WriteLine(
string? value) => this.sb.AppendLine(value?.
ToString());
469 public override void WriteLine(StringBuilder? value) => this.sb.AppendLine(value?.
ToString());
470 public override void WriteLine(
object? value) => this.sb.AppendLine(value?.
ToString());
471 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg0));
472 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format,
object? arg0,
object? arg1) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg0, arg1));
473 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));
474 public override void WriteLine([StringSyntax(StringSyntaxAttribute.CompositeFormat)]
string format, params
object?[] arg) => this.sb.AppendLine(
string.Format(this.FormatProvider, format, arg));
475 public override Task WriteLineAsync(
char value) { this.sb.AppendLine(value.ToString());
return Task.CompletedTask; }
476 public override Task WriteLineAsync(
string? value) { this.sb.AppendLine(value);
return Task.CompletedTask; }
477 public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken =
default) { this.sb.AppendLine(value?.
ToString());
return Task.CompletedTask; }
478 public override Task WriteLineAsync(
char[] buffer,
int index,
int count) { this.sb.AppendLine(
new string(buffer, index, count));
return Task.CompletedTask; }
479 public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken =
default) { this.sb.AppendLine(
new string(buffer.Span));
return Task.CompletedTask; }
480 public override Task WriteLineAsync() { this.sb.AppendLine(
string.Empty);
return Task.CompletedTask; }
484 private async Task DestroyXmppClient()
486 this.reconnectTimer?.Dispose();
487 this.reconnectTimer =
null;
489 await this.OnConnectionStateChanged(
XmppState.Offline);
491 if (this.xmppFilteredEventSink is not
null)
496 this.xmppFilteredEventSink =
null;
499 this.contractsClient?.
Dispose();
500 this.contractsClient =
null;
502 this.fileUploadClient?.
Dispose();
503 this.fileUploadClient =
null;
505 this.thingRegistryClient?.
Dispose();
506 this.thingRegistryClient =
null;
508 this.provisioningClient?.
Dispose();
509 this.provisioningClient =
null;
512 this.eDalerClient =
null;
514 this.neuroFeaturesClient?.
Dispose();
515 this.neuroFeaturesClient =
null;
517 this.pushNotificationClient?.
Dispose();
518 this.pushNotificationClient =
null;
521 this.sensorClient =
null;
524 this.controlClient =
null;
526 this.concentratorClient?.
Dispose();
527 this.concentratorClient =
null;
530 this.pepClient =
null;
533 this.abuseClient =
null;
535#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE || DEBUG_NFC_REMOTE
536 this.debugSniffer =
null;
539 if (this.debugEventSink is not
null)
542 this.debugEventSink?.
Dispose();
543 this.debugEventSink =
null;
546 if (this.xmppClient is not
null)
548 await this.xmppClient.DisposeAsync();
549 this.xmppClient =
null;
553 private bool XmppStale()
555 return this.xmppClient is
null ||
556 this.xmppClient.State == XmppState.Offline ||
557 this.xmppClient.State == XmppState.Error ||
558 (this.xmppClient.State != XmppState.Connected && (DateTime.Now - this.xmppLastStateChange).TotalSeconds >= 10);
565#if DEBUG_XMPP_REMOTE || DEBUG_DB_REMOTE || DEBUG_NFC_REMOTE
566 if (this.debugSniffer is
null)
569 return [this.debugSniffer];
577 private bool XmppParametersCurrent()
579 if (this.xmppClient is
null)
618 private void RecreateReconnectTimer()
620 this.reconnectTimer?.Dispose();
627 [Obsolete(
"Use the DisposeAsync method.")]
628 public void Dispose()
630 this.DisposeAsync().Wait();
636 public async Task DisposeAsync()
638 this.reconnectTimer?.Dispose();
639 this.reconnectTimer =
null;
641 if (this.xmppFilteredEventSink is not
null)
646 this.xmppFilteredEventSink =
null;
649 this.contractsClient?.
Dispose();
650 this.contractsClient =
null;
652 this.fileUploadClient?.
Dispose();
653 this.fileUploadClient =
null;
655 this.thingRegistryClient?.
Dispose();
656 this.thingRegistryClient =
null;
658 this.provisioningClient?.
Dispose();
659 this.provisioningClient =
null;
662 this.eDalerClient =
null;
664 this.neuroFeaturesClient?.
Dispose();
665 this.neuroFeaturesClient =
null;
667 this.pushNotificationClient?.
Dispose();
668 this.pushNotificationClient =
null;
671 this.sensorClient =
null;
674 this.controlClient =
null;
676 this.concentratorClient?.
Dispose();
677 this.concentratorClient =
null;
680 this.pepClient =
null;
683 this.abuseClient =
null;
685 if (this.xmppClient is not
null)
687 await this.xmppClient.DisposeAsync();
688 this.xmppClient =
null;
728 public async Task<bool> WaitForConnectedState(TimeSpan Timeout)
730 if (this.xmppClient is
null)
732 DateTime Start = DateTime.Now;
734 while (this.xmppClient is
null && DateTime.Now - Start < Timeout)
735 await Task.Delay(1000);
737 if (this.xmppClient is
null)
740 Timeout -= DateTime.Now - Start;
743 if (this.xmppClient.State ==
XmppState.Connected)
746 if (Timeout < TimeSpan.Zero)
749 int i = await this.xmppClient.WaitStateAsync((
int)Timeout.TotalMilliseconds,
XmppState.Connected);
753 public override Task Load(
bool IsResuming, CancellationToken CancellationToken)
755 if (this.
BeginLoad(IsResuming, CancellationToken))
759 ServiceRef.TagProfile.StepChanged += this.TagProfile_StepChanged;
760 ServiceRef.TagProfile.Changed += this.TagProfile_Changed;
762 _ = this.CreateClientAsync();
773 return Task.CompletedTask;
776 private async Task CreateClientAsync()
781 await this.CreateXmppClient();
783 if ((this.xmppClient is not
null) &&
784 this.xmppClient.State ==
XmppState.Connected &&
798 public override Task Unload()
800 return this.Unload(
false);
803 public Task UnloadFast()
805 return this.Unload(
true);
808 private async Task Unload(
bool fast)
814 ServiceRef.TagProfile.StepChanged -= this.TagProfile_StepChanged;
815 ServiceRef.TagProfile.Changed -= this.TagProfile_Changed;
817 this.reconnectTimer?.Dispose();
818 this.reconnectTimer =
null;
820 if (this.xmppClient is not
null)
822 this.xmppClient.CheckConnection =
false;
840 await this.DestroyXmppClient();
851 private void TagProfile_StepChanged(
object? Sender, EventArgs e)
856 Task ExecutionTask = Task.Run(async () =>
862 if (CreateXmppClient && !this.XmppParametersCurrent())
863 await this.CreateXmppClient();
864 else if (!CreateXmppClient)
865 await this.DestroyXmppClient();
874 private void TagProfile_Changed(
object? Sender, PropertyChangedEventArgs e)
877 this.TagProfile_StepChanged(Sender,
new EventArgs());
880 private Task XmppClient_Error(
object?
_, Exception e)
882 this.LatestError = e.Message;
883 return Task.CompletedTask;
886 private Task XmppClient_ConnectionError(
object?
_, Exception e)
888 if (e is ObjectDisposedException)
892 this.reconnectTimer?.Dispose();
893 this.reconnectTimer =
null;
894 this.LatestConnectionError = e.Message;
897 this.LatestConnectionError = e.Message;
899 return Task.CompletedTask;
902 private async Task XmppClient_StateChanged(
object? Sender,
XmppState NewState)
904 this.xmppLastStateChange = DateTime.Now;
909 this.LatestError =
string.Empty;
910 this.LatestConnectionError =
string.Empty;
914 this.LatestError =
string.Empty;
915 this.LatestConnectionError =
string.Empty;
917 this.xmppConnected =
true;
919 this.RecreateReconnectTimer();
924 this.xmppClient?.PasswordHash ??
string.Empty,
925 this.xmppClient?.PasswordHashMethod ??
string.Empty);
932 this.RegisterContractsEventHandlers();
934 if (!await this.contractsClient.
LoadKeys(
false))
936 this.contractsClient.
Dispose();
937 this.contractsClient =
null;
951 ManagePresenceSubscriptionRequests =
false
954 this.provisioningClient.CanControlQuestion += this.ProvisioningClient_CanControlQuestion;
955 this.provisioningClient.CanReadQuestion += this.ProvisioningClient_CanReadQuestion;
956 this.provisioningClient.IsFriendQuestion += this.ProvisioningClient_IsFriendQuestion;
962 this.RegisterEDalerEventHandlers(this.eDalerClient);
968 this.RegisterNeuroFeatureEventHandlers(this.neuroFeaturesClient);
977 this.ReregisterPepEventHandlers(this.pepClient);
986 if (this.xmppFilteredEventSink is not
null)
994 this.xmppConnected =
false;
998 if (this.xmppClient is not
null && !this.xmppClient.Disposed)
999 await this.xmppClient.Reconnect();
1009 await this.OnConnectionStateChanged(NewState);
1015 public event EventHandlerAsync<XmppState>? ConnectionStateChanged;
1017 private async Task OnConnectionStateChanged(
XmppState NewState)
1019 await this.ConnectionStateChanged.Raise(
this, NewState);
1026 public bool IsLoggedOut {
get;
private set; }
1027 public bool IsOnline => (this.xmppClient is not
null) && this.xmppClient.State ==
XmppState.Connected;
1029 public string BareJid =>
this.xmppClient?.BareJID ??
string.Empty;
1031 public string? LatestError {
get;
private set; }
1032 public string? LatestConnectionError {
get;
private set; }
1038 private enum ConnectOperation
1041 ConnectAndCreateAccount,
1045 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnect(
string domain,
bool isIpAddress,
string hostName,
int portNumber,
1046 string languageCode, Assembly applicationAssembly, Func<XmppClient, Task> connectedFunc)
1048 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber,
string.Empty,
string.Empty,
string.Empty, languageCode,
1049 string.Empty,
string.Empty, applicationAssembly, connectedFunc, ConnectOperation.Connect);
1052 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectAndCreateAccount(
string domain,
bool isIpAddress,
string hostName,
1053 int portNumber,
string userName,
string password,
string languageCode,
string ApiKey,
string ApiSecret,
1054 Assembly applicationAssembly, Func<XmppClient, Task> connectedFunc)
1056 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber, userName, password,
string.Empty, languageCode,
1057 ApiKey, ApiSecret, applicationAssembly, connectedFunc, ConnectOperation.ConnectAndCreateAccount);
1060 public Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectAndConnectToAccount(
string domain,
bool isIpAddress,
string hostName,
1061 int portNumber,
string userName,
string password,
string passwordMethod,
string languageCode, Assembly applicationAssembly,
1062 Func<XmppClient, Task> connectedFunc)
1064 return this.TryConnectInner(domain, isIpAddress, hostName, portNumber, userName, password, passwordMethod, languageCode,
1065 string.Empty,
string.Empty, applicationAssembly, connectedFunc, ConnectOperation.ConnectToAccount);
1068 private async Task<(
bool Succeeded,
string? ErrorMessage,
string[]? Alternatives)> TryConnectInner(
string Domain,
bool IsIpAddress,
string HostName,
1069 int PortNumber,
string UserName,
string Password,
string PasswordMethod,
string LanguageCode,
string ApiKey,
string ApiSecret,
1070 Assembly ApplicationAssembly, Func<XmppClient, Task> ConnectedFunc, ConnectOperation Operation)
1073 TaskCompletionSource<bool> Tcs =
new(TaskCreationOptions.RunContinuationsAsynchronously);
1076 bool StreamNegotiation =
false, StreamOpened =
false, StartingEncryption =
false, Authenticating =
false, Registering =
false, IsTimeout =
false;
1077 string? ConnectionError =
null;
1078 string? ErrorMessage =
null;
1079 string[]? Alternatives =
null;
1085 void TrySetResult(
bool result)
1088 if (Interlocked.CompareExchange(ref Disposed, 0, 0) == 0)
1089 Tcs.TrySetResult(result);
1093 Task OnConnectionError(
object?
_, Exception ex)
1095 if (Interlocked.CompareExchange(ref Disposed, 0, 0) == 1)
1096 return Task.CompletedTask;
1100 case ObjectDisposedException:
1104 this.reconnectTimer?.Dispose();
1105 this.reconnectTimer =
null;
1111 ConnectionError = ex.Message;
1115 TrySetResult(
false);
1116 return Task.CompletedTask;
1120 async Task OnStateChanged(
object?
_,
XmppState newState)
1122 if (Interlocked.CompareExchange(ref Disposed, 0, 0) == 1)
1128 StreamNegotiation =
true;
1131 StreamOpened =
true;
1134 StartingEncryption =
true;
1137 Authenticating =
true;
1138 if (Operation == ConnectOperation.Connect)
1148 TrySetResult(
false);
1153 TrySetResult(
false);
1160 if (
string.IsNullOrEmpty(PasswordMethod))
1161 Client =
new XmppClient(HostName, PortNumber, UserName, Password, LanguageCode, ApplicationAssembly, this.sniffer);
1163 Client =
new XmppClient(HostName, PortNumber, UserName, Password, PasswordMethod, LanguageCode, ApplicationAssembly, this.sniffer);
1165 if (Operation == ConnectOperation.ConnectAndCreateAccount)
1167 if (!
string.IsNullOrEmpty(ApiKey) && !
string.IsNullOrEmpty(ApiSecret))
1173 Client.TrustServer = !IsIpAddress;
1174 Client.AllowCramMD5 =
false;
1175 Client.AllowDigestMD5 =
false;
1176 Client.AllowPlain =
false;
1177 Client.AllowEncryption =
true;
1178 Client.AllowScramSHA1 =
true;
1179 Client.AllowScramSHA256 =
true;
1180 Client.AllowQuickLogin =
true;
1183 Client.OnConnectionError += OnConnectionError;
1184 Client.OnStateChanged += OnStateChanged;
1187 Task ConnectTask = Client.
Connect(IsIpAddress ?
string.Empty : Domain);
1192 Task CompletedTask = await Task.WhenAny(Tcs.Task, ConnectTask, Task.Delay(TimeSpan.FromSeconds(5), Cts.Token));
1193 bool Succeeded =
false;
1195 if (CompletedTask == Tcs.Task)
1197 Succeeded = Tcs.Task.Result;
1199 else if (CompletedTask == ConnectTask)
1203 Succeeded = await Tcs.Task;
1209 TrySetResult(
false);
1214 if (Succeeded && ConnectedFunc is not
null)
1215 await ConnectedFunc(Client);
1218 Interlocked.Exchange(ref Disposed, 1);
1219 Client.OnStateChanged -= OnStateChanged;
1220 Client.OnConnectionError -= OnConnectionError;
1226 if (!Succeeded &&
string.IsNullOrEmpty(ErrorMessage))
1228 if (this.sniffer is not
null)
1229 System.Diagnostics.Debug.WriteLine(await this.sniffer.SnifferToTextAsync(),
"Sniffer");
1231 if (!StreamNegotiation || IsTimeout)
1233 else if (!StreamOpened)
1235 else if (!StartingEncryption)
1237 else if (!Authenticating)
1239 else if (!Registering)
1241 if (!
string.IsNullOrWhiteSpace(ConnectionError))
1242 ErrorMessage = ConnectionError;
1246 else if (Operation == ConnectOperation.ConnectAndCreateAccount)
1248 else if (Operation == ConnectOperation.ConnectToAccount)
1254 return (Succeeded, ErrorMessage, Alternatives);
1256 catch (Exception ex)
1258 ServiceRef.
LogService.LogException(ex,
new KeyValuePair<string, object?>(nameof(ConnectOperation), Operation.ToString()));
1264 if (Client is not
null)
1268 Interlocked.Exchange(ref Disposed, 1);
1269 Client.OnStateChanged -= OnStateChanged;
1270 Client.OnConnectionError -= OnConnectionError;
1280 private void ReconnectTimer_Tick(
object?
_)
1282 if (this.xmppClient is
null)
1288 if (this.XmppStale())
1290 this.xmppLastStateChange = DateTime.Now;
1292 if (!this.xmppClient.Disposed)
1293 SafeFireAndForget(this.xmppClient.Reconnect());
1300 private static void SafeFireAndForget(Task task)
1305 _ = task.ContinueWith(t =>
1307 if (t.Exception is not
null)
1309 }, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.RunContinuationsAsynchronously);
1320 public Task<bool> ChangePassword(
string NewPassword)
1322 TaskCompletionSource<bool> PasswordChanged =
new();
1326 PasswordChanged.TrySetResult(e.Ok);
1327 return Task.CompletedTask;
1330 return PasswordChanged.Task;
1339 public async Task<bool> TryGenerateAndChangePassword()
1341 bool ChangeSucceeded =
false;
1346 if (await this.ChangePassword(NewPassword))
1349 ChangeSucceeded =
true;
1352 catch (Exception Ex)
1359 if (ChangeSucceeded)
1361 this.updatePasswordTimer?.Dispose();
1362 this.updatePasswordTimer =
null;
1366 this.RecreateUpdatePasswordTimer();
1369 return ChangeSucceeded;
1373 private async
void UpdatePasswordTimer_Tick(
object?
_)
1375 if (this.xmppClient is
null)
1381 await this.TryGenerateAndChangePassword();
1384 private void RecreateUpdatePasswordTimer()
1386 this.updatePasswordTimer?.Dispose();
1392 #region Components & Services
1399 public Task<ServiceDiscoveryEventArgs> SendServiceDiscoveryRequest(
string FullJid)
1401 TaskCompletionSource<ServiceDiscoveryEventArgs> Result =
new();
1405 Result.TrySetResult(e);
1406 return Task.CompletedTask;
1417 public async Task<bool> DiscoverServices(
XmppClient? Client =
null)
1419 Client ??= this.xmppClient;
1430 catch (Exception ex)
1432 if (this.sniffer is not
null)
1434 string CommsDump = await this.sniffer.SnifferToTextAsync();
1435 ServiceRef.
LogService.LogException(ex,
new KeyValuePair<string, object?>(
"Sniffer", CommsDump));
1441 List<Task> Tasks = [];
1442 object SynchObject =
new();
1444 Tasks.Add(CheckFeatures(Client, SynchObject));
1447 Tasks.Add(CheckComponent(Client,
Item, SynchObject));
1449 await Task.WhenAll([.. Tasks]);
1475 private static async Task CheckFeatures(
XmppClient Client,
object SynchObject)
1485 private static async Task CheckComponent(
XmppClient Client,
Item Item,
object SynchObject)
1492 ServiceRef.TagProfile.LegalJid =
Item.
JID;
1495 ServiceRef.TagProfile.RegistryJid =
Item.
JID;
1501 ServiceRef.TagProfile.ProvisioningJid =
Item.
JID;
1511 ServiceRef.TagProfile.LogJid =
Item.
JID;
1514 ServiceRef.TagProfile.LogJid =
Item.
JID;
1517 ServiceRef.TagProfile.EDalerJid =
Item.
JID;
1520 ServiceRef.TagProfile.NeuroFeaturesJid =
Item.
JID;
1523 ServiceRef.TagProfile.PubSubJid =
Item.
JID;
1543 string[] Codes = CodesGenerated.Split(
CommonTypes.
CRLF, StringSplitOptions.RemoveEmptyEntries);
1545 if (Array.IndexOf<
string>(Codes, Code) < 0)
1548 await this.DestroyXmppClient();
1550 this.domainName =
string.Empty;
1551 this.accountName =
string.Empty;
1552 this.passwordHash =
string.Empty;
1553 this.passwordHashMethod =
string.Empty;
1554 this.xmppConnected =
false;
1569 public async Task AddTransferCode(
string Code)
1573 if (
string.IsNullOrEmpty(CodesGenerated))
1574 CodesGenerated = Code;
1576 CodesGenerated +=
"\r\n" + Code;
1584 #region Presence Subscriptions
1586 private async Task XmppClient_OnPresenceSubscribe(
object? Sender,
PresenceEventArgs e)
1589 string FriendlyName =
string.IsNullOrWhiteSpace(e.
NickName) ? e.FromBareJID : e.
NickName;
1590 string? PhotoUrl =
null;
1592 int PhotoHeight = 0;
1594 foreach (XmlNode N
in e.
Presence.ChildNodes)
1599 if (RemoteIdentity is not
null)
1609 Log.
Warning(
"Invalid ID received. Presence subscription declined.", e.
FromBareJID, RemoteIdentity.
Id,
"IdValidationError",
1610 new KeyValuePair<string, object?>(
"Recipient JID",
this.BareJid),
1611 new KeyValuePair<string, object?>(
"Sender JID", e.
FromBareJID),
1612 new KeyValuePair<string, object?>(
"Legal ID", RemoteIdentity.
Id),
1613 new KeyValuePair<string, object?>(
"Validation", Status));
1630 if (Info.
FriendlyName != FriendlyName || ((RemoteIdentity is not
null) && Info.
LegalId != RemoteIdentity.
Id))
1632 if (RemoteIdentity is not
null)
1634 Info.LegalId = RemoteIdentity.
Id;
1635 Info.LegalIdentity = RemoteIdentity;
1638 Info.FriendlyName = FriendlyName;
1645 if ((RemoteIdentity is not
null) && (RemoteIdentity.
Attachments is not
null))
1647 (PhotoUrl, PhotoWidth, PhotoHeight) = await PhotosLoader.LoadPhotoAsTemporaryFile(RemoteIdentity.
Attachments,
1666 AllowSubscriptionFrom =
true,
1668 FriendlyName =
string.IsNullOrWhiteSpace(e.
NickName) ? e.FromBareJID : e.
NickName,
1676 Info.AllowSubscriptionFrom =
true;
1690 if (SubscribeTo.HasValue && SubscribeTo.Value)
1695 IdXml =
string.Empty;
1698 StringBuilder Xml =
new();
1700 IdXml = Xml.ToString();
1711 if (this.abuseClient is
null)
1726 AllowSubscriptionFrom =
false,
1728 FriendlyName =
string.IsNullOrWhiteSpace(e.
NickName) ? e.FromBareJID : e.
NickName,
1736 Info.AllowSubscriptionFrom =
false;
1750 TaskCompletionSource<bool> Result =
new();
1754 Result.TrySetResult(e.
Ok);
1755 return Task.CompletedTask;
1769 await this.OnPresenceSubscribe.Raise(
this, e);
1772 private async Task XmppClient_OnPresenceUnsubscribed(
object? Sender,
PresenceEventArgs e)
1777 ContactInfo.AllowSubscriptionFrom =
null;
1781 await this.OnPresenceUnsubscribed.Raise(
this, e);
1786 #region IQ Stanzas (Information Query)
1796 public Task<XmlElement> IqSetAsync(
string To,
string Xml)
1808 if (this.xmppClient is
null)
1809 throw new Exception(
"Not connected to XMPP network.");
1811 return this.xmppClient;
1834 public void SendMessage(
QoSLevel QoS,
Waher.
Networking.
XMPP.MessageType Type,
string Id,
string To,
string CustomXml,
string Body,
1835 string Subject,
string Language,
string ThreadId,
string ParentThreadId, EventHandlerAsync<DeliveryEventArgs>? DeliveryCallback,
object? State)
1837 this.
XmppClient.
SendMessage(QoS, Type, Id, To, CustomXml, Body, Subject, Language, ThreadId, ParentThreadId, DeliveryCallback, State);
1841 private Task XmppClient_OnNormalMessage(
object? Sender,
MessageEventArgs e)
1844 new KeyValuePair<string, object?>(
"Stanza", e.
Message.OuterXml));
1846 return Task.CompletedTask;
1849 private async Task XmppClient_OnChatMessage(
object? Sender,
MessageEventArgs e)
1853 foreach (XmlNode N
in e.
Message.ChildNodes)
1855 if (N is XmlElement
E &&
1856 E.LocalName ==
"qlRef" &&
1858 RemoteBareJid.IndexOf(
'@') < 0 &&
1859 RemoteBareJid.IndexOf(
'/') < 0)
1863 foreach (XmlNode N2
in E.ChildNodes)
1865 if (N2 is XmlElement E2 &&
1866 E2.LocalName ==
"identity" &&
1874 if (RemoteIdentity is not
null)
1876 IdentityStatus Status = await this.ValidateIdentity(RemoteIdentity);
1879 Log.
Warning(
"Message rejected because the embedded legal identity was not valid.",
1880 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1881 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1882 new KeyValuePair<string, object?>(
"Status", Status));
1886 string Jid = RemoteIdentity[
"JID"];
1888 if (
string.IsNullOrEmpty(Jid))
1890 Log.
Warning(
"Message rejected because the embedded legal identity lacked JID.",
1891 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1892 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1893 new KeyValuePair<string, object?>(
"Status", Status));
1897 if (!
string.Equals(
XML.
Attribute(
E,
"bareJid",
string.Empty), Jid, StringComparison.OrdinalIgnoreCase))
1899 Log.
Warning(
"Message rejected because the embedded legal identity had a different JID compared to the JID of the quick-login reference.",
1900 new KeyValuePair<string, object?>(
"Identity", RemoteIdentity.
Id),
1901 new KeyValuePair<string, object?>(
"From", RemoteBareJid),
1902 new KeyValuePair<string, object?>(
"Status", Status));
1906 RemoteBareJid = Jid;
1913 string? ReplaceObjectId =
null;
1918 RemoteBareJid = RemoteBareJid,
1919 RemoteObjectId = e.
Id,
1921 Html =
string.Empty,
1923 Markdown = string.Empty
1926 foreach (XmlNode N
in e.
Message.ChildNodes)
1928 if (N is XmlElement
E)
1930 switch (N.LocalName)
1933 if (
E.NamespaceURI ==
"urn:xmpp:content")
1939 case "text/markdown":
1940 Message.Markdown =
E.InnerText;
1944 Message.PlainText =
E.InnerText;
1948 Message.Html =
E.InnerText;
1955 if (
E.NamespaceURI ==
"http://jabber.org/protocol/xhtml-im")
1957 string Html =
E.InnerXml;
1959 int i = Html.IndexOf(
"<body", StringComparison.OrdinalIgnoreCase);
1962 i = Html.IndexOf(
'>', i + 5);
1964 Html = Html[(i + 1)..].TrimStart();
1966 i = Html.LastIndexOf(
"</body>", StringComparison.OrdinalIgnoreCase);
1968 Html = Html[..i].TrimEnd();
1971 Message.Html = Html;
1976 if (
E.NamespaceURI ==
"urn:xmpp:message-correct:0")
1982 E.HasAttribute(
"stamp") &&
1983 XML.
TryParse(
E.GetAttribute(
"stamp"), out DateTime Timestamp2))
1985 Message.Created = Timestamp2.ToUniversalTime();
1992 if (!
string.IsNullOrEmpty(Message.
Markdown))
1998 AllowScriptTag =
false,
1999 EmbedEmojis =
false,
2000 AudioAutoplay =
false,
2001 AudioControls =
false,
2002 ParseMetaData =
false,
2003 VideoAutoplay =
false,
2004 VideoControls =
false
2009 if (
string.IsNullOrEmpty(Message.
PlainText))
2012 if (
string.IsNullOrEmpty(Message.
Html))
2015 catch (Exception ex)
2018 Message.Markdown =
string.Empty;
2022 if (
string.IsNullOrEmpty(ReplaceObjectId))
2032 ReplaceObjectId =
null;
2037 Old.Updated = Message.
Created;
2038 Old.Html = Message.
Html;
2048 MainThread.BeginInvokeOnMainThread(async () =>
2052 string.Equals(
ChatViewModel.BareJid, RemoteBareJid, StringComparison.OrdinalIgnoreCase))
2054 if (
string.IsNullOrEmpty(ReplaceObjectId))
2070 EntityId = RemoteBareJid,
2071 CorrelationId = RemoteBareJid,
2072 Presentation = NotificationPresentation.StoreOnly
2082 string Message = e.Body ??
string.Empty;
2085 if (!
string.IsNullOrEmpty(e.
Code))
2089 string Key =
"ClientMessage" + e.
Code;
2092 if (!
string.IsNullOrEmpty(LocalizedMessage) && !LocalizedMessage.Equals(Key, StringComparison.Ordinal))
2094 Message = LocalizedMessage;
2106 MainThread.BeginInvokeOnMainThread(async () =>
2113 if (AppId is not
null)
2119 catch (Exception Ex2)
2130 if (AppId is not
null)
2132 Ref = All.FirstOrDefault(r =>
string.Equals(r.CreatedIdentityId, AppId.
Id, StringComparison.OrdinalIgnoreCase));
2136 .Where(r => r.CreatedIdentityState ==
IdentityState.Created && !
string.IsNullOrEmpty(r.CreatedIdentityId))
2137 .OrderByDescending(r => r.UpdatedUtc)
2141 .Where(r => !
string.IsNullOrEmpty(r.CreatedIdentityId))
2142 .OrderByDescending(r => r.UpdatedUtc)
2145 catch (Exception Ex3)
2151 if (Ref is not
null && Review is not
null)
2157 await Vm.ApplyApplicationReviewAsync(Review);
2161 catch (Exception Ex)
2236 Message = Message.Trim();
2238 bool ShouldShowAlert = Review is
null ||
2239 (Review.InvalidClaims.Length == 0 &&
2240 Review.InvalidPhotos.Length == 0 &&
2241 Review.UnvalidatedClaims.Length == 0 &&
2242 Review.UnvalidatedPhotos.Length == 0);
2244 if (ShouldShowAlert)
2246 MainThread.BeginInvokeOnMainThread(async () =>
2254 return Task.CompletedTask;
2267 ReceivedUtc = DateTime.UtcNow
2272 IEnumerable<InvalidClaim> InvalidClaimsEnumerable = e.InvalidClaims as IEnumerable<InvalidClaim> ?? Array.Empty<
InvalidClaim>();
2273 List<string> InvalidClaimNames = [];
2274 List<ApplicationReviewClaimDetail> InvalidClaimDetailList = [];
2282 if (ClaimValue.Length == 0)
2285 InvalidClaimNames.Add(ClaimValue);
2289 InvalidClaim.Reason ??
string.Empty,
2292 InvalidClaim.Service ??
string.Empty);
2293 InvalidClaimDetailList.Add(Detail);
2296 Candidate.InvalidClaims = InvalidClaimNames.Count > 0 ? [.. InvalidClaimNames] : [];
2297 Candidate.InvalidClaimDetails = InvalidClaimDetailList.Count > 0 ? [.. InvalidClaimDetailList] : [];
2306 IEnumerable<InvalidPhoto> InvalidPhotosEnumerable = e.InvalidPhotos as IEnumerable<InvalidPhoto> ?? Array.Empty<
InvalidPhoto>();
2307 List<string> InvalidPhotoNames = [];
2308 List<ApplicationReviewPhotoDetail> InvalidPhotoDetailList = [];
2316 if (FileName.Length == 0)
2319 string FileNameWithoutExtension = Path.GetFileNameWithoutExtension(FileName);
2320 string DisplayName =
string.IsNullOrEmpty(FileNameWithoutExtension) ? FileName : FileNameWithoutExtension;
2321 DisplayName = DisplayName.Trim();
2322 if (DisplayName.Length == 0)
2323 DisplayName = FileName;
2325 InvalidPhotoNames.Add(DisplayName);
2330 InvalidPhoto.Reason ??
string.Empty,
2333 InvalidPhoto.Service ??
string.Empty);
2334 InvalidPhotoDetailList.Add(Detail);
2337 Candidate.InvalidPhotos = InvalidPhotoNames.Count > 0 ? [.. InvalidPhotoNames] : [];
2338 Candidate.InvalidPhotoDetails = InvalidPhotoDetailList.Count > 0 ? [.. InvalidPhotoDetailList] : [];
2347 IEnumerable<string> UnvalidatedClaimsEnumerable = e.UnvalidatedClaims as IEnumerable<string> ?? [];
2348 List<string> UnvalidatedClaimList = [];
2349 foreach (
string Claim
in UnvalidatedClaimsEnumerable)
2351 if (
string.IsNullOrWhiteSpace(Claim))
2354 string TrimmedClaim = Claim.Trim();
2355 if (TrimmedClaim.Length > 0)
2356 UnvalidatedClaimList.Add(TrimmedClaim);
2359 Candidate.UnvalidatedClaims = UnvalidatedClaimList.Count > 0 ? [.. UnvalidatedClaimList] : [];
2368 IEnumerable<string> UnvalidatedPhotosEnumerable = e.UnvalidatedPhotos as IEnumerable<string> ?? [];
2369 List<string> UnvalidatedPhotoList = [];
2370 foreach (
string Photo in UnvalidatedPhotosEnumerable)
2372 if (
string.IsNullOrWhiteSpace(
Photo))
2375 string TrimmedPhoto =
Photo.Trim();
2376 if (TrimmedPhoto.Length > 0)
2377 UnvalidatedPhotoList.Add(TrimmedPhoto);
2380 Candidate.UnvalidatedPhotos = UnvalidatedPhotoList.Count > 0 ? [.. UnvalidatedPhotoList] : [];
2387 bool HasMeaningfulData =
2388 !
string.IsNullOrEmpty(Candidate.
Message) ||
2389 !
string.IsNullOrEmpty(Candidate.
Code) ||
2390 Candidate.InvalidClaims.Length > 0 ||
2391 Candidate.InvalidPhotos.Length > 0 ||
2392 Candidate.UnvalidatedClaims.Length > 0 ||
2393 Candidate.UnvalidatedPhotos.Length > 0;
2395 return HasMeaningfulData ? Candidate :
null;
2397 catch (Exception Ex)
2408 await this.OnPresence.Raise(
this, e);
2414 public event EventHandlerAsync<PresenceEventArgs>? OnPresence;
2419 public event EventHandlerAsync<PresenceEventArgs>? OnPresenceSubscribe;
2424 public event EventHandlerAsync<PresenceEventArgs>? OnPresenceUnsubscribed;
2430 public void RequestPresenceSubscription(
string BareJid)
2440 public void RequestPresenceSubscription(
string BareJid,
string CustomXml)
2449 public void RequestPresenceUnsubscription(
string BareJid)
2458 public void RequestRevokePresenceSubscription(
string BareJid)
2470 public RosterItem[] Roster => this.xmppClient?.Roster ?? [];
2477 public RosterItem? GetRosterItem(
string BareJid)
2495 public void RemoveRosterItem(
string BareJid)
2500 private async Task XmppClient_OnRosterItemAdded(
object? Sender,
RosterItem Item)
2502 await this.OnRosterItemAdded.Raise(
this,
Item);
2508 public event EventHandlerAsync<RosterItem>? OnRosterItemAdded;
2510 private async Task XmppClient_OnRosterItemUpdated(
object? Sender,
RosterItem Item)
2512 await this.OnRosterItemUpdated.Raise(
this,
Item);
2518 public event EventHandlerAsync<RosterItem>? OnRosterItemUpdated;
2520 private async Task XmppClient_OnRosterItemRemoved(
object? Sender,
RosterItem Item)
2522 await this.OnRosterItemRemoved.Raise(
this,
Item);
2528 public event EventHandlerAsync<RosterItem>? OnRosterItemRemoved;
2532 #region Push Notification
2537 public bool SupportsPushNotification => this.pushNotificationClient is not
null;
2547 if (this.pushNotificationClient is
null)
2550 return this.pushNotificationClient;
2563 if (this.pushNotificationClient is
null || !this.IsOnline ||
string.IsNullOrEmpty(
TokenInformation.
Token))
2587 public Task ClearPushNotificationRules()
2603 string Channel,
string MessageVariable,
string PatternMatchingScript,
string ContentScript)
2606 PatternMatchingScript, ContentScript);
2620 public async Task<string?> GetApiToken(
int Seconds)
2622 DateTime
Now = DateTime.UtcNow;
2624 if (!
string.IsNullOrEmpty(this.token) &&
Now.Subtract(
this.tokenCreated).TotalSeconds < Seconds - 10)
2629 if (!await this.WaitForConnectedState(TimeSpan.FromSeconds(20)))
2633 if (this.httpxClient is
null)
2634 throw new Exception(
"Not connected to XMPP network.");
2637 this.tokenCreated =
Now;
2651 public async Task<object> PostToProtectedApi(
string LocalResource,
object Data, params KeyValuePair<string, string>[] Headers)
2653 StringBuilder Url =
new();
2656 Url.Append(
"httpx://");
2657 else if (!
string.IsNullOrEmpty(this.token))
2659 Url.Append(
"https://");
2661 KeyValuePair<string, string> Authorization =
new(
"Authorization",
"Bearer " + this.token);
2663 if (Headers is
null)
2664 Headers = [Authorization];
2667 int c = Headers.Length;
2669 Array.Resize(ref Headers, c + 1);
2670 Headers[c] = Authorization;
2674 throw new IOException(
"No connection and no token available for call to protect API.");
2677 Url.Append(LocalResource);
2687 #region HTTP File Upload
2697 if (this.fileUploadClient is
null)
2700 return this.fileUploadClient;
2707 public bool FileUploadIsSupported
2713 return ServiceRef.TagProfile.FileUploadIsSupported &&
2714 this.fileUploadClient is not
null &&
2717 catch (Exception ex)
2731 public Task<HttpFileUploadEventArgs> RequestUploadSlotAsync(
string FileName,
string ContentType,
long ContentSize)
2733 return this.FileUploadClient.RequestUploadSlotAsync(FileName, ContentType, ContentSize);
2739 #region Personal Eventing Protocol (PEP)
2741 private readonly LinkedList<KeyValuePair<Type, EventHandlerAsync<PersonalEventNotificationEventArgs>>> pepHandlers =
new();
2751 if (this.pepClient is
null)
2754 return this.pepClient;
2763 public void RegisterPepHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
2765 lock (this.pepHandlers)
2767 this.pepHandlers.AddLast(
new KeyValuePair<Type, EventHandlerAsync<PersonalEventNotificationEventArgs>>(PersonalEventType, Handler));
2779 public bool UnregisterPepHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
2781 lock (this.pepHandlers)
2783 LinkedListNode<KeyValuePair<Type, EventHandlerAsync<PersonalEventNotificationEventArgs>>>? Node = this.pepHandlers.First;
2785 while (Node is not
null)
2787 if (Node.Value.Key == PersonalEventType &&
2788 (Node.Value.Value.Target?.Equals(Handler.Target) ?? Handler.Target is
null) &&
2789 Node.Value.Value.Method.Equals(Handler.Method))
2791 this.pepHandlers.Remove(Node);
2804 lock (this.pepHandlers)
2806 foreach (KeyValuePair<Type, EventHandlerAsync<PersonalEventNotificationEventArgs>> P
in this.pepHandlers)
2813 #region Thing Registries & Discovery
2823 if (this.thingRegistryClient is
null)
2826 return this.thingRegistryClient;
2840 public bool IsIoTDiscoClaimURI(
string DiscoUri)
2850 public bool IsIoTDiscoSearchURI(
string DiscoUri)
2860 public bool IsIoTDiscoDirectURI(
string DiscoUri)
2871 public bool TryDecodeIoTDiscoClaimURI(
string DiscoUri, [NotNullWhen(
true)] out
MetaDataTag[]? Tags)
2883 public bool TryDecodeIoTDiscoSearchURI(
string DiscoUri, [NotNullWhen(
true)] out
SearchOperator[]? Operators,
2884 out
string? RegistryJid)
2891 List<SearchOperator> List = [];
2895 if (Operator.Name.Equals(
"R", StringComparison.OrdinalIgnoreCase))
2897 if (!
string.IsNullOrEmpty(RegistryJid))
2903 RegistryJid = StrEqOp.Value;
2909 Operators = [.. List];
2924 public bool TryDecodeIoTDiscoDirectURI(
string DiscoUri, [NotNullWhen(
true)] out
string? Jid, out
string? SourceId, out
string? NodeId,
2925 out
string? PartitionId, [NotNullWhen(
true)] out
MetaDataTag[]? Tags)
2938 List<MetaDataTag> TagsFound = [];
2944 switch (S.Name.ToUpper(CultureInfo.InvariantCulture))
2959 PartitionId = S.Value;
2976 Tags = [.. TagsFound];
2978 return !
string.IsNullOrEmpty(Jid);
2987 public Task<NodeResultEventArgs> ClaimThing(
string DiscoUri,
bool MakePublic)
2989 if (!this.TryDecodeIoTDiscoClaimURI(DiscoUri, out
MetaDataTag[]? Tags))
2992 TaskCompletionSource<NodeResultEventArgs> Result =
new();
2996 Result.TrySetResult(e);
2997 return Task.CompletedTask;
3012 public Task<bool> Disown(
string RegistryJid,
string ThingJid,
string SourceId,
string Partition,
string NodeId)
3014 TaskCompletionSource<bool> Result =
new();
3018 Result.TrySetResult(e.
Ok);
3019 return Task.CompletedTask;
3032 public async Task<(
SearchResultThing[],
string?, bool)> Search(
int Offset,
int MaxCount,
string DiscoUri)
3034 if (!this.TryDecodeIoTDiscoSearchURI(DiscoUri, out
SearchOperator[]? Operators, out
string? RegistryJid))
3037 (
SearchResultThing[] Things,
bool More) = await this.Search(Offset, MaxCount, RegistryJid, Operators);
3039 return (Things, RegistryJid, More);
3057 Result.TrySetResult((e.Things, e.More));
3059 Result.TrySetException(e.StanzaError ?? new Exception(
"Unable to perform search."));
3061 return Task.CompletedTask;
3074 if (!this.TryDecodeIoTDiscoSearchURI(DiscoUri, out
SearchOperator[]? Operators, out
string? RegistryJid))
3079 return (Things, RegistryJid);
3088 public async Task<SearchResultThing[]> SearchAll(
string? RegistryJid, params
SearchOperator[] Operators)
3094 List<SearchResultThing> Result = [];
3095 int Offset = Things.Length;
3097 Result.AddRange(Things);
3102 Result.AddRange(Things);
3103 Offset += Things.Length;
3111 #region Legal Identities
3116 public async Task GenerateNewKeys()
3128 public async Task<IdApplicationAttributesEventArgs> GetIdApplicationAttributes()
3140 public async Task<LegalIdentity> AddLegalIdentity(
RegisterIdentityModel Model,
bool GenerateNewKeys,
3153 public async Task<LegalIdentity> AddLegalIdentity(
Property[] Props,
bool GenerateNewKeys,
3156 if (GenerateNewKeys)
3157 await this.GenerateNewKeys();
3177 public async Task<LegalIdentity[]> GetLegalIdentities(
XmppClient? client =
null)
3211 return (Info is not
null && Info.
LegalIdentity is not
null);
3250 public async Task PetitionIdentity(
CaseInsensitiveString LegalId,
string PetitionId,
string Purpose)
3253 throw new Exception(
"No Legal Identity registered.");
3257 this.StartPetition(PetitionId);
3261 private void StartPetition(
string PetitionId)
3263 lock (this.currentPetitions)
3265 this.currentPetitions[PetitionId] =
true;
3269 private bool EndPetition(
string PetitionId)
3271 lock (this.currentPetitions)
3273 return this.currentPetitions.Remove(PetitionId);
3284 public Task SendPetitionIdentityResponse(
CaseInsensitiveString LegalId,
string PetitionId,
string RequestorFullJid,
bool Response)
3292 public event EventHandlerAsync<LegalIdentityEventArgs>? LegalIdentityChanged;
3297 public event EventHandlerAsync<LegalIdentityEventArgs>? IdentityApplicationChanged;
3304 if (Ref is not
null)
3306 Ref.UpdatedUtc = DateTime.UtcNow;
3315 Model.Loader.Reload();
3318 catch (Exception Ex)
3331 await this.LegalIdentityChanged.Raise(
this, e);
3335 MainThread.BeginInvokeOnMainThread(async () =>
3343 catch (Exception ex)
3346 await
App.StopAsync();
3359 await this.IdentityApplicationChanged.Raise(
this, e);
3365 if (ToObsolete is not
null)
3373 if (!
string.Equals(Intent.
EntityId, ToObsolete.
Id, StringComparison.OrdinalIgnoreCase))
3383 await this.LegalIdentityChanged.Raise(
this, e);
3384 await this.IdentityApplicationChanged.Raise(
this, e);
3386 if (ToObsolete is not
null && !ToObsolete.IsDiscarded())
3387 await this.ObsoleteLegalIdentity(ToObsolete.
Id);
3392 await this.IdentityApplicationChanged.Raise(
this, e);
3401 await this.LegalIdentityChanged.Raise(
this, e);
3404 catch (Exception ex)
3445 Presentation = NotificationPresentation.StoreOnly
3452 catch (Exception ex)
3461 public event EventHandlerAsync<LegalIdentityPetitionEventArgs>? PetitionForIdentityReceived;
3476 Presentation = NotificationPresentation.StoreOnly
3479 Intent.
Extras[
"petitionId"] = e.PetitionId ??
string.Empty;
3480 Intent.
Extras[
"requestedIdentityId"] = e.RequestedIdentityId ??
string.Empty;
3484 await this.PetitionForIdentityReceived.Raise(
this, e);
3490 public event EventHandlerAsync<LegalIdentityPetitionResponseEventArgs>? PetitionedIdentityResponseReceived;
3497 await this.PetitionedIdentityResponseReceived.Raise(
this, e);
3499 catch (Exception ex)
3510 public Task ExportSigningKeys(XmlWriter Output)
3520 public Task<bool> ImportSigningKeys(XmlElement Xml)
3538 #region Smart Contracts
3540 private readonly Dictionary<CaseInsensitiveString, DateTime> lastContractEvent = [];
3550 if (this.contractsClient is
null)
3553 return this.contractsClient;
3557 private void RegisterContractsEventHandlers()
3561 this.ContractsClient.IdentityUpdated += this.ContractsClient_IdentityUpdated;
3562 this.ContractsClient.PetitionForIdentityReceived += this.ContractsClient_PetitionForIdentityReceived;
3563 this.ContractsClient.PetitionedIdentityResponseReceived += this.ContractsClient_PetitionedIdentityResponseReceived;
3564 this.ContractsClient.PetitionForContractReceived += this.ContractsClient_PetitionForContractReceived;
3565 this.ContractsClient.PetitionedContractResponseReceived += this.ContractsClient_PetitionedContractResponseReceived;
3566 this.ContractsClient.PetitionForSignatureReceived += this.ContractsClient_PetitionForSignatureReceived;
3567 this.ContractsClient.PetitionedSignatureResponseReceived += this.ContractsClient_PetitionedSignatureResponseReceived;
3568 this.ContractsClient.PetitionForPeerReviewIDReceived += this.ContractsClient_PetitionForPeerReviewIdReceived;
3569 this.ContractsClient.PetitionedPeerReviewIDResponseReceived += this.ContractsClient_PetitionedPeerReviewIdResponseReceived;
3570 this.ContractsClient.PetitionClientUrlReceived += this.ContractsClient_PetitionClientUrlReceived;
3571 this.ContractsClient.ContractProposalReceived += this.ContractsClient_ContractProposalReceived;
3572 this.ContractsClient.ContractUpdated += this.ContractsClient_ContractUpdated;
3573 this.ContractsClient.ContractSigned += this.ContractsClient_ContractSigned;
3574 this.ContractsClient.ClientMessage += this.ContractsClient_ClientMessage;
3591 public async Task<string[]> GetCreatedContractReferences()
3593 List<string> Result = [];
3594 string[] ContractIds;
3601 Result.AddRange(ContractIds);
3602 Nr = ContractIds.Length;
3614 public async Task<string[]> GetSignedContractReferences()
3616 List<string> Result = [];
3617 string[] ContractIds;
3624 Result.AddRange(ContractIds);
3625 Nr = ContractIds.Length;
3646 lock (this.currentTransactions)
3649 string Currency =
Contract[
"Currency"]?.ToString() ??
string.Empty;
3656 await UpdateContractReference(Result);
3668 await UpdateContractReference(Result);
3687 public async Task<Contract> CreateContract(
3696 DateTime? SignAfter,
3697 DateTime? SignBefore,
3698 bool CanActAsTemplate)
3700 Contract Result = await this.
ContractsClient.
CreateContractAsync(TemplateId, Parts,
Parameters, Visibility, PartsMode,
Duration, ArchiveRequired, ArchiveOptional, SignAfter, SignBefore, CanActAsTemplate);
3701 await UpdateContractReference(Result);
3725 this.StartPetition(PetitionId);
3736 public Task SendPetitionContractResponse(
CaseInsensitiveString ContractId,
string PetitionId,
string RequestorFullJid,
bool Response)
3744 public event EventHandlerAsync<ContractPetitionEventArgs>? PetitionForContractReceived;
3759 Presentation = NotificationPresentation.StoreOnly
3762 Intent.
Extras[
"contractId"] = e.RequestedContractId ??
string.Empty;
3763 Intent.
Extras[
"petitionId"] = e.PetitionId ??
string.Empty;
3766 await this.PetitionForContractReceived.Raise(
this, e);
3772 public event EventHandlerAsync<ContractPetitionResponseEventArgs>? PetitionedContractResponseReceived;
3779 await this.PetitionedContractResponseReceived.Raise(
this, e);
3781 catch (Exception ex)
3795 lock (this.lastContractEvent)
3797 if (this.lastContractEvent.TryGetValue(ContractId, out DateTime TP))
3800 return DateTime.MinValue;
3813 ContractId = Contract.ContractId
3831 public event EventHandlerAsync<ContractProposalEventArgs>? ContractProposalReceived;
3846 Presentation = NotificationPresentation.StoreOnly
3849 Intent.
Extras[
"role"] = e.Role ??
string.Empty;
3850 Intent.
Extras[
"fromJid"] = e.FromBareJID ??
string.Empty;
3853 await this.ContractProposalReceived.Raise(
this, e);
3859 public event EventHandlerAsync<ContractReferenceEventArgs>? ContractUpdated;
3863 await this.ContractUpdatedOrSigned(e);
3876 Presentation = NotificationPresentation.StoreOnly
3880 await this.ContractUpdated.Raise(
this, e);
3885 lock (this.lastContractEvent)
3887 this.lastContractEvent[e.
ContractId] = DateTime.Now;
3890 return Task.CompletedTask;
3896 public event EventHandlerAsync<ContractSignedEventArgs>? ContractSigned;
3900 await this.ContractUpdatedOrSigned(e);
3913 Presentation = NotificationPresentation.StoreOnly
3917 await this.ContractSigned.Raise(
this, e);
3943 public Task<KeyValuePair<string, TemporaryFile>> GetAttachment(
string Url,
SignWith SignWith, TimeSpan Timeout)
3963 this.StartPetition(PetitionId);
3982 public event EventHandlerAsync<SignaturePetitionEventArgs>? PetitionForPeerReviewIdReceived;
3986 await this.PetitionForPeerReviewIdReceived.Raise(
this, e);
3992 public event EventHandlerAsync<SignaturePetitionResponseEventArgs>? PetitionedPeerReviewIdResponseReceived;
3999 await this.PetitionedPeerReviewIdResponseReceived.Raise(
this, e);
4001 catch (Exception ex)
4012 public async Task<ServiceProviderWithLegalId[]> GetServiceProvidersForPeerReviewAsync()
4018 catch (Exception Ex)
4032 public async Task SelectPeerReviewService(
string ServiceId,
string ServiceProvider)
4037 private readonly Dictionary<string, bool> currentPetitions = [];
4041 lock (this.currentPetitions)
4043 if (!this.currentPetitions.ContainsKey(e.
PetitionId))
4045 ServiceRef.
LogService.LogWarning(
"Client URL message for a petition is ignored. Petition ID not recognized.",
4046 new KeyValuePair<string, object?>(
"PetitionId", e.
PetitionId),
4047 new KeyValuePair<string, object?>(
"ClientUrl", e.
ClientUrl));
4065 public Task<byte[]> Sign(
byte[] data,
SignWith signWith)
4079 public bool? ValidateSignature(
LegalIdentity legalIdentity,
byte[] data,
byte[] signature)
4094 public Task SendPetitionSignatureResponse(
CaseInsensitiveString LegalId,
byte[] Content,
byte[]
Signature,
string PetitionId,
string RequestorFullJid,
bool Response)
4102 public event EventHandlerAsync<SignaturePetitionEventArgs>? PetitionForSignatureReceived;
4117 Presentation = NotificationPresentation.StoreOnly
4120 byte[] ContentToSign = e.ContentToSign ?? [];
4121 string ContentToSignBase64 = Convert.ToBase64String(ContentToSign);
4122 string Purpose = e.Purpose ??
string.Empty;
4125 Intent.
Extras[
"signatoryId"] = e.SignatoryIdentityId ??
string.Empty;
4126 Intent.
Extras[
"petitionId"] = e.PetitionId ??
string.Empty;
4127 Intent.
Extras[
"requestorIdentityId"] = RequestorIdentityId;
4128 Intent.
Extras[
"purpose"] = Purpose;
4129 Intent.
Extras[
"contentToSign"] = ContentToSignBase64;
4132 await this.PetitionForSignatureReceived.Raise(
this, e);
4138 public event EventHandlerAsync<SignaturePetitionResponseEventArgs>? SignaturePetitionResponseReceived;
4145 await this.SignaturePetitionResponseReceived.Raise(
this, e);
4147 catch (Exception ex)
4156 #region Provisioning
4166 if (this.provisioningClient is
null)
4169 return this.provisioningClient;
4173 private async Task ProvisioningClient_IsFriendQuestion(
object? Sender,
IsFriendEventArgs e)
4175 if (e.
From.IndexOfAny(clientChars) < 0)
4187 CorrelationId = e.Key
4194 private async Task ProvisioningClient_CanReadQuestion(
object? Sender,
CanReadEventArgs e)
4196 if (e.
From.IndexOfAny(clientChars) < 0)
4208 CorrelationId = e.Key
4215 private async Task ProvisioningClient_CanControlQuestion(
object? Sender,
CanControlEventArgs e)
4217 if (e.
From.IndexOfAny(clientChars) < 0)
4229 CorrelationId = e.Key
4236 private static readonly
char[] clientChars = [
'@',
'/'];
4254 public void IsFriendResponse(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool IsFriend,
4255 RuleRange Range, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4272 public void CanControlResponseAll(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool CanControl,
4273 string[]? ParameterNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4276 Node, Callback, State);
4291 public void CanControlResponseCaller(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4292 bool CanControl,
string[]? ParameterNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4295 ParameterNames, Node, Callback, State);
4310 public void CanControlResponseDomain(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4311 bool CanControl,
string[]? ParameterNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4314 ParameterNames, Node, Callback, State);
4330 public void CanControlResponseDevice(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4331 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4335 ParameterNames,
Token, Node, Callback, State);
4351 public void CanControlResponseService(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4352 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4356 ParameterNames,
Token, Node, Callback, State);
4372 public void CanControlResponseUser(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4373 bool CanControl,
string[]? ParameterNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4377 ParameterNames,
Token, Node, Callback, State);
4393 public void CanReadResponseAll(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
bool CanRead,
4394 FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4397 Node, Callback, State);
4413 public void CanReadResponseCaller(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4414 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4417 FieldTypes, FieldNames, Node, Callback, State);
4433 public void CanReadResponseDomain(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4434 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4437 FieldTypes, FieldNames, Node, Callback, State);
4454 public void CanReadResponseDevice(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4455 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4459 FieldTypes, FieldNames,
Token, Node, Callback, State);
4476 public void CanReadResponseService(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4477 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4481 FieldTypes, FieldNames,
Token, Node, Callback, State);
4498 public void CanReadResponseUser(
string ProvisioningServiceJID,
string JID,
string RemoteJID,
string Key,
4499 bool CanRead,
FieldType FieldTypes,
string[]? FieldNames,
string Token,
IThingReference Node, EventHandlerAsync<IqResultEventArgs> Callback,
4503 FieldTypes, FieldNames,
Token, Node, Callback, State);
4516 public void DeleteDeviceRules(
string ServiceJID,
string DeviceJID,
string NodeId,
string SourceId,
string Partition,
4517 EventHandlerAsync<IqResultEventArgs> Callback,
object? State)
4534 if (this.sensorClient is
null)
4537 return this.sensorClient;
4549 if (this.controlClient is
null)
4552 return this.controlClient;
4564 if (this.concentratorClient is
null)
4567 return this.concentratorClient;
4584 Result.TrySetResult((e.Things, e.More));
4588 return Task.CompletedTask;
4598 public async Task<SearchResultThing[]> GetAllMyDevices()
4604 List<SearchResultThing> Result = [];
4605 int Offset = Things.Length;
4607 Result.AddRange(Things);
4612 Result.AddRange(Things);
4613 Offset += Things.Length;
4627 public void GetCertificate(
string Token, EventHandlerAsync<CertificateEventArgs> Callback,
object? State)
4640 public void GetControlForm(
string To,
string Language, EventHandlerAsync<DataFormEventArgs> Callback,
object? State,
4652 public Task<SensorDataClientRequest> RequestSensorReadout(
string Destination,
FieldType Types)
4673 private readonly Dictionary<string, Wallet.Transaction> currentTransactions = [];
4674 private Balance? lastBalance =
null;
4675 private DateTime lastEDalerEvent = DateTime.MinValue;
4685 if (this.eDalerClient is
null)
4688 return this.eDalerClient;
4692 private void RegisterEDalerEventHandlers(
EDalerClient Client)
4694 Client.BalanceUpdated += this.EDalerClient_BalanceUpdated;
4695 Client.BuyEDalerOptionsClientUrlReceived += this.NeuroWallet_BuyEDalerOptionsClientUrlReceived;
4696 Client.BuyEDalerOptionsCompleted += this.NeuroWallet_BuyEDalerOptionsCompleted;
4697 Client.BuyEDalerOptionsError += this.NeuroWallet_BuyEDalerOptionsError;
4698 Client.BuyEDalerClientUrlReceived += this.NeuroWallet_BuyEDalerClientUrlReceived;
4699 Client.BuyEDalerCompleted += this.NeuroWallet_BuyEDalerCompleted;
4700 Client.BuyEDalerError += this.NeuroWallet_BuyEDalerError;
4701 Client.SellEDalerOptionsClientUrlReceived += this.NeuroWallet_SellEDalerOptionsClientUrlReceived;
4702 Client.SellEDalerOptionsCompleted += this.NeuroWallet_SellEDalerOptionsCompleted;
4703 Client.SellEDalerOptionsError += this.NeuroWallet_SellEDalerOptionsError;
4704 Client.SellEDalerClientUrlReceived += this.NeuroWallet_SellEDalerClientUrlReceived;
4705 Client.SellEDalerCompleted += this.NeuroWallet_SellEDalerCompleted;
4706 Client.SellEDalerError += this.NeuroWallet_SellEDalerError;
4712 this.lastEDalerEvent = DateTime.Now;
4725 Presentation = NotificationPresentation.StoreOnly
4729 await this.EDalerBalanceUpdated.Raise(
this, e);
4735 public event EventHandlerAsync<BalanceEventArgs>? EDalerBalanceUpdated;
4740 public Balance? LastEDalerBalance => this.lastBalance;
4745 public DateTime LastEDalerEvent => this.lastEDalerEvent;
4754 public bool TryParseEDalerUri(
string Uri, out
EDalerUri Parsed, out
string Reason)
4767 public async Task<string> TryDecryptMessage(
byte[] EncryptedMessage,
byte[] PublicKey, Guid TransactionId,
string RemoteEndpoint,
bool LocalIsRecipient)
4773 catch (Exception ex)
4776 return string.Empty;
4795 public Task<(
AccountEvent[], bool)> GetEDalerAccountEvents(
int MaxCount)
4806 public Task<(
AccountEvent[], bool)> GetEDalerAccountEvents(
int MaxCount, DateTime From)
4815 public Task<Balance> GetEDalerBalance()
4824 public Task<(decimal, string,
PendingPayment[])> GetPendingEDalerPayments()
4838 public Task<string> CreateFullEDalerPaymentUri(
string ToBareJid, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays)
4840 this.lastEDalerEvent = DateTime.Now;
4854 public Task<string> CreateFullEDalerPaymentUri(
string ToBareJid, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays,
string Message)
4856 this.lastEDalerEvent = DateTime.Now;
4869 public Task<string> CreateFullEDalerPaymentUri(
LegalIdentity To, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays)
4871 this.lastEDalerEvent = DateTime.Now;
4885 public Task<string> CreateFullEDalerPaymentUri(
LegalIdentity To, decimal Amount, decimal? AmountExtra,
string Currency,
int ValidNrDays,
string PrivateMessage)
4887 this.lastEDalerEvent = DateTime.Now;
4900 public string CreateIncompleteEDalerPayMeUri(
string BareJid, decimal? Amount, decimal? AmountExtra,
string Currency,
string Message)
4915 public string CreateIncompleteEDalerPayMeUri(
LegalIdentity To, decimal? Amount, decimal? AmountExtra,
string Currency,
string PrivateMessage)
4924 public async Task<IBuyEDalerServiceProvider[]> GetServiceProvidersForBuyingEDalerAsync()
4936 public async Task<OptionsTransaction> InitiateBuyEDalerGetOptions(
string ServiceId,
string ServiceProvider)
4938 string TransactionId = Guid.NewGuid().ToString();
4939 string SuccessUrl = await GenerateNeuroAccessUrl(
4940 new KeyValuePair<string, object?>(
"cmd",
"beos"),
4941 new KeyValuePair<string, object?>(
"tid", TransactionId),
4946 string FailureUrl = await GenerateNeuroAccessUrl(
4947 new KeyValuePair<string, object?>(
"cmd",
"beof"),
4948 new KeyValuePair<string, object?>(
"tid", TransactionId),
4953 string CancelUrl = await GenerateNeuroAccessUrl(
4954 new KeyValuePair<string, object?>(
"cmd",
"beoc"),
4955 new KeyValuePair<string, object?>(
"tid", TransactionId),
4964 lock (this.currentTransactions)
4966 this.currentTransactions[TransactionId] = Result;
4974 lock (this.currentTransactions)
4978 ServiceRef.
LogService.LogWarning(
"Client URL message for getting options for buying eDaler ignored. Transaction ID not recognized.",
4979 new KeyValuePair<string, object?>(
"TransactionId", e.
TransactionId),
4980 new KeyValuePair<string, object?>(
"ClientUrl", e.
ClientUrl));
4985 await Wallet.Transaction.OpenUrl(e.
ClientUrl);
4991 return Task.CompletedTask;
4999 public void BuyEDalerGetOptionsCompleted(
string TransactionId, IDictionary<CaseInsensitiveString, object>[] Options)
5003 lock (this.currentTransactions)
5005 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5008 this.currentTransactions.Remove(TransactionId);
5018 return Task.CompletedTask;
5026 public void BuyEDalerGetOptionsFailed(
string TransactionId,
string Message)
5030 lock (this.currentTransactions)
5032 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5035 this.currentTransactions.Remove(TransactionId);
5049 public async Task<PaymentTransaction> InitiateBuyEDaler(
string ServiceId,
string ServiceProvider, decimal Amount,
string Currency)
5051 string TransactionId = Guid.NewGuid().ToString();
5052 string SuccessUrl = await GenerateNeuroAccessUrl(
5053 new KeyValuePair<string, object?>(
"cmd",
"bes"),
5054 new KeyValuePair<string, object?>(
"tid", TransactionId),
5055 new KeyValuePair<string, object?>(
"amt", Amount),
5056 new KeyValuePair<string, object?>(
"cur", Currency),
5061 string FailureUrl = await GenerateNeuroAccessUrl(
5062 new KeyValuePair<string, object?>(
"cmd",
"bef"),
5063 new KeyValuePair<string, object?>(
"tid", TransactionId),
5068 string CancelUrl = await GenerateNeuroAccessUrl(
5069 new KeyValuePair<string, object?>(
"cmd",
"bec"),
5070 new KeyValuePair<string, object?>(
"tid", TransactionId),
5079 lock (this.currentTransactions)
5081 this.currentTransactions[TransactionId] = Result;
5087 private static async Task<string> GenerateNeuroAccessUrl(params KeyValuePair<string, object?>[] Claims)
5090 return Constants.UriSchemes.NeuroAccess +
":" +
Token;
5095 lock (this.currentTransactions)
5099 ServiceRef.
LogService.LogWarning(
"Client URL message for buying eDaler ignored. Transaction ID not recognized.",
5100 new KeyValuePair<string, object?>(
"TransactionId", e.
TransactionId),
5101 new KeyValuePair<string, object?>(
"ClientUrl", e.
ClientUrl));
5106 await Wallet.Transaction.OpenUrl(e.
ClientUrl);
5112 return Task.CompletedTask;
5121 public void BuyEDalerCompleted(
string TransactionId, decimal Amount,
string Currency)
5125 lock (this.currentTransactions)
5127 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5130 this.currentTransactions.Remove(TransactionId);
5140 return Task.CompletedTask;
5148 public void BuyEDalerFailed(
string TransactionId,
string Message)
5152 lock (this.currentTransactions)
5154 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5157 this.currentTransactions.Remove(TransactionId);
5167 public async Task<ISellEDalerServiceProvider[]> GetServiceProvidersForSellingEDalerAsync()
5179 public async Task<OptionsTransaction> InitiateSellEDalerGetOptions(
string ServiceId,
string ServiceProvider)
5181 string TransactionId = Guid.NewGuid().ToString();
5182 string SuccessUrl = await GenerateNeuroAccessUrl(
5183 new KeyValuePair<string, object?>(
"cmd",
"seos"),
5184 new KeyValuePair<string, object?>(
"tid", TransactionId),
5189 string FailureUrl = await GenerateNeuroAccessUrl(
5190 new KeyValuePair<string, object?>(
"cmd",
"seof"),
5191 new KeyValuePair<string, object?>(
"tid", TransactionId),
5196 string CancelUrl = await GenerateNeuroAccessUrl(
5197 new KeyValuePair<string, object?>(
"cmd",
"seoc"),
5198 new KeyValuePair<string, object?>(
"tid", TransactionId),
5207 lock (this.currentTransactions)
5209 this.currentTransactions[TransactionId] = Result;
5217 lock (this.currentTransactions)
5221 ServiceRef.
LogService.LogWarning(
"Client URL message for getting options for selling eDaler ignored. Transaction ID not recognized.",
5222 new KeyValuePair<string, object?>(
"TransactionId", e.
TransactionId),
5223 new KeyValuePair<string, object?>(
"ClientUrl", e.
ClientUrl));
5228 await Wallet.Transaction.OpenUrl(e.
ClientUrl);
5234 return Task.CompletedTask;
5242 public void SellEDalerGetOptionsCompleted(
string TransactionId, IDictionary<CaseInsensitiveString, object>[] Options)
5246 lock (this.currentTransactions)
5248 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5251 this.currentTransactions.Remove(TransactionId);
5261 return Task.CompletedTask;
5269 public void SellEDalerGetOptionsFailed(
string TransactionId,
string Message)
5273 lock (this.currentTransactions)
5275 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5278 this.currentTransactions.Remove(TransactionId);
5292 public async Task<PaymentTransaction> InitiateSellEDaler(
string ServiceId,
string ServiceProvider, decimal Amount,
string Currency)
5294 string TransactionId = Guid.NewGuid().ToString();
5295 string SuccessUrl = await GenerateNeuroAccessUrl(
5296 new KeyValuePair<string, object?>(
"cmd",
"ses"),
5297 new KeyValuePair<string, object?>(
"tid", TransactionId),
5298 new KeyValuePair<string, object?>(
"amt", Amount),
5299 new KeyValuePair<string, object?>(
"cur", Currency),
5304 string FailureUrl = await GenerateNeuroAccessUrl(
5305 new KeyValuePair<string, object?>(
"cmd",
"sef"),
5306 new KeyValuePair<string, object?>(
"tid", TransactionId),
5311 string CancelUrl = await GenerateNeuroAccessUrl(
5312 new KeyValuePair<string, object?>(
"cmd",
"sec"),
5313 new KeyValuePair<string, object?>(
"tid", TransactionId),
5322 lock (this.currentTransactions)
5324 this.currentTransactions[TransactionId] = Result;
5332 lock (this.currentTransactions)
5337 new KeyValuePair<string, object?>(
"TransactionId", e.
TransactionId),
5338 new KeyValuePair<string, object?>(
"ClientUrl", e.
ClientUrl));
5343 await Wallet.Transaction.OpenUrl(e.
ClientUrl);
5349 return Task.CompletedTask;
5357 public void SellEDalerFailed(
string TransactionId,
string Message)
5361 lock (this.currentTransactions)
5363 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5366 this.currentTransactions.Remove(TransactionId);
5375 return Task.CompletedTask;
5384 public void SellEDalerCompleted(
string TransactionId, decimal Amount,
string Currency)
5388 lock (this.currentTransactions)
5390 if (!this.currentTransactions.TryGetValue(TransactionId, out
Transaction))
5393 this.currentTransactions.Remove(TransactionId);
5402 #region Neuro-Features
5404 private DateTime lastTokenEvent = DateTime.MinValue;
5413 if (this.neuroFeaturesClient is
null)
5416 return this.neuroFeaturesClient;
5422 Client.TokenAdded += this.NeuroFeaturesClient_TokenAdded;
5423 Client.TokenRemoved += this.NeuroFeaturesClient_TokenRemoved;
5425 Client.StateUpdated += this.NeuroFeaturesClient_StateUpdated;
5426 Client.VariablesUpdated += this.NeuroFeaturesClient_VariablesUpdated;
5432 public DateTime LastNeuroFeatureEvent => this.lastTokenEvent;
5436 this.lastTokenEvent = DateTime.Now;
5447 EntityId = e.Token?.TokenId,
5448 CorrelationId = e.Token?.TokenId,
5449 Presentation = NotificationPresentation.StoreOnly
5453 await this.NeuroFeatureRemoved.Raise(
this, e);
5463 this.lastTokenEvent = DateTime.Now;
5474 EntityId = e.Token?.TokenId,
5475 CorrelationId = e.Token?.TokenId,
5476 Presentation = NotificationPresentation.StoreOnly
5480 await this.NeuroFeatureAdded.Raise(
this, e);
5490 await this.NeuroFeatureVariablesUpdated.Raise(
this, e);
5496 public event EventHandlerAsync<VariablesUpdatedEventArgs>? NeuroFeatureVariablesUpdated;
5500 await this.NeuroFeatureStateUpdated.Raise(
this, e);
5506 public event EventHandlerAsync<NewStateEventArgs>? NeuroFeatureStateUpdated;
5512 public Task<TokensEventArgs> GetNeuroFeatures()
5514 return this.GetNeuroFeatures(0,
int.MaxValue);
5523 public Task<TokensEventArgs> GetNeuroFeatures(
int Offset,
int MaxCount)
5532 public Task<string[]> GetNeuroFeatureReferences()
5534 return this.GetNeuroFeatureReferences(0,
int.MaxValue);
5543 public Task<string[]> GetNeuroFeatureReferences(
int Offset,
int MaxCount)
5552 public Task<TokenTotalsEventArgs> GetNeuroFeatureTotals()
5562 public Task<TokensEventArgs> GetNeuroFeaturesForContract(
string ContractId)
5574 public Task<TokensEventArgs> GetNeuroFeaturesForContract(
string ContractId,
int Offset,
int MaxCount)
5584 public Task<string[]> GetNeuroFeatureReferencesForContract(
string ContractId)
5596 public Task<string[]> GetNeuroFeatureReferencesForContract(
string ContractId,
int Offset,
int MaxCount)
5606 public Task<Token> GetNeuroFeature(
string TokenId)
5616 public Task<TokenEvent[]> GetNeuroFeatureEvents(
string TokenId)
5618 return this.GetNeuroFeatureEvents(TokenId, 0,
int.MaxValue);
5628 public Task<TokenEvent[]> GetNeuroFeatureEvents(
string TokenId,
int Offset,
int MaxCount)
5638 public Task AddNeuroFeatureTextNote(
string TokenId,
string TextNote)
5640 return this.AddNeuroFeatureTextNote(TokenId, TextNote,
false);
5651 public Task AddNeuroFeatureTextNote(
string TokenId,
string TextNote,
bool Personal)
5653 this.lastTokenEvent = DateTime.Now;
5663 public Task AddNeuroFeatureXmlNote(
string TokenId,
string XmlNote)
5665 return this.AddNeuroFeatureXmlNote(TokenId, XmlNote,
false);
5676 public Task AddNeuroFeatureXmlNote(
string TokenId,
string XmlNote,
bool Personal)
5678 this.lastTokenEvent = DateTime.Now;
5687 public Task<CreationAttributesEventArgs> GetNeuroFeatureCreationAttributes()
5696 public async Task<string> GenerateNeuroFeatureStateDiagramReport(
string TokenId)
5709 public async Task<VerticalStackLayout> GenerateNeuroFeatureStateDiagramReportMaui(
string TokenId)
5722 public async Task<string> GenerateNeuroFeatureProfilingReport(
string TokenId)
5735 public async Task<VerticalStackLayout> GenerateNeuroFeatureProfilingReportMaui(
string TokenId)
5748 public async Task<string> GenerateNeuroFeaturePresentReport(
string TokenId)
5761 public async Task<VerticalStackLayout> GenerateNeuroFeaturePresentReportMaui(
string TokenId)
5774 public async Task<string> GenerateNeuroFeatureHistoryReport(
string TokenId)
5786 public async Task<VerticalStackLayout> GenerateNeuroFeatureHistoryReportMaui(
string TokenId)
5801 public Task<CurrentStateEventArgs> GetNeuroFeatureCurrentState(
string TokenId)
5817 public Task SavePrivateXml(
string Xml)
5819 return this.xmppClient?.SetPrivateXmlElementAsync(Xml)
5820 ??
throw new Exception(
"Not connected to XMPP network.");
5830 public Task SavePrivateXml(XmlElement Xml)
5832 return this.xmppClient?.SetPrivateXmlElementAsync(Xml)
5833 ??
throw new Exception(
"Not connected to XMPP network.");
5843 public async Task<XmlElement?> LoadPrivateXml(
string LocalName,
string Namespace)
5853 public Task DeletePrivateXml(
string LocalName,
string Namespace)
5855 StringBuilder Xml =
new();
5859 Xml.Append(
" xmlns='");
5862 return this.SavePrivateXml(Xml.ToString());
5876 if (this.pepClient is
null)
5886 public async Task<Item[]?> GetAllNodeIdsAsync()
5890 TaskCompletionSource<ServiceItemsDiscoveryEventArgs> Tcs =
new();
5893 (s, e) => { Tcs.TrySetResult(e);
return Task.CompletedTask; },
5896 return Result.
Items;
5905 public async Task<PubSubItem[]?> GetItemsAsync(
string NodeId)
5909 TaskCompletionSource<ItemsEventArgs> Tcs =
new();
5912 return Result.
Items;
5921 public async Task<PubSubItem[]?> GetItemsAsync(
string NodeId,
string[] ItemIds)
5925 TaskCompletionSource<ItemsEventArgs> Tcs =
new();
5928 return Result.
Items;
5937 public async Task<PubSubItem?> GetItemAsync(
string NodeId,
string ItemId)
5941 TaskCompletionSource<ItemsEventArgs> Tcs =
new();
5944 return Result.
Items.FirstOrDefault();
5953 public async Task<PubSubItem[]?> GetLatestItemsAsync(
string NodeId,
int Count)
5957 TaskCompletionSource<ItemsEventArgs> Tcs =
new();
5960 return Result.
Items;
5969 public async Task<PubSubPageResult?> GetItemsPageAsync(
string NodeId,
string? ServiceAddress =
null,
string? After =
null,
string? Before =
null,
int? Index =
null,
int? Max =
null)
5974 bool HasCursor = !
string.IsNullOrWhiteSpace(After) || !
string.IsNullOrWhiteSpace(Before) || Index.HasValue || Max.HasValue;
5980 TaskCompletionSource<ItemsEventArgs> Tcs =
new();
5985 if (
string.IsNullOrWhiteSpace(EffectiveServiceAddress))
5991 await this.
PubSubClient.
GetItems(EffectiveServiceAddress, NodeId, (s, e) => HandleResult(e, Tcs),
null);
5996 if (
string.IsNullOrWhiteSpace(EffectiveServiceAddress))
6002 await this.
PubSubClient.
GetItems(EffectiveServiceAddress, NodeId, Query, (s, e) => HandleResult(e, Tcs),
null);
6009 return new PubSubPageResult(NodeId, Items, Page);
6025 return await Tcs.Task;
6031 try {
return await this.CreateNodeAsync(NodeId, Config); }
6032 catch {
return null; }
6040 return await Tcs.Task;
6046 try {
return await this.DeleteNodeAsync(NodeId, RedirectUri); }
6047 catch {
return null; }
6051 public async Task<SubscriptionEventArgs> SubscribeAsync(
string NodeId,
string? Jid =
null,
SubscriptionOptions? Options =
null)
6053 TaskCompletionSource<SubscriptionEventArgs> Tcs =
new();
6054 if (Options is
null)
6058 return await Tcs.Task;
6062 public async Task<SubscriptionEventArgs?> TrySubscribeAsync(
string NodeId,
string? Jid =
null,
SubscriptionOptions? Options =
null)
6064 try {
return await this.SubscribeAsync(NodeId, Jid, Options); }
6065 catch {
return null; }
6069 public async Task<SubscriptionEventArgs> UnsubscribeAsync(
string NodeId,
string? Jid =
null,
string? SubscriptionId =
null)
6071 TaskCompletionSource<SubscriptionEventArgs> Tcs =
new();
6073 return await Tcs.Task;
6077 public async Task<SubscriptionEventArgs?> TryUnsubscribeAsync(
string NodeId,
string? Jid =
null,
string? SubscriptionId =
null)
6079 try {
return await this.UnsubscribeAsync(NodeId, Jid, SubscriptionId); }
6080 catch {
return null; }
6084 public async Task<ItemResultEventArgs> PublishAsync(
string NodeId,
string? ItemId =
null,
string PayloadXml =
"")
6086 TaskCompletionSource<ItemResultEventArgs> Tcs =
new();
6087 await this.
PubSubClient.
Publish(NodeId, ItemId ??
string.Empty, PayloadXml, (s, e) => HandleResult(e, Tcs),
null);
6088 return await Tcs.Task;
6092 public async Task<ItemResultEventArgs?> TryPublishAsync(
string NodeId,
string? ItemId =
null,
string PayloadXml =
"")
6094 try {
return await this.PublishAsync(NodeId, ItemId, PayloadXml); }
6095 catch {
return null; }
6099 public async Task<IqResultEventArgs> RetractAsync(
string NodeId,
string ItemId)
6101 TaskCompletionSource<IqResultEventArgs> Tcs =
new();
6103 return await Tcs.Task;
6107 public async Task<IqResultEventArgs?> TryRetractAsync(
string NodeId,
string ItemId)
6109 try {
return await this.RetractAsync(NodeId, ItemId); }
6110 catch {
return null; }
6118 return await Tcs.Task;
6124 try {
return await this.PurgeNodeAsync(NodeId); }
6125 catch {
return null; }
6128 private static Task HandleResult<T>(T e, TaskCompletionSource<T> Tcs) where T :
IqResultEventArgs
6131 Tcs.TrySetResult(e);
6133 Tcs.TrySetException(e.
StanzaError ??
new Exception());
6134 return Task.CompletedTask;
6146 catch (Exception Ex)
6152 private static string ToBareJid(
string Jid)
6154 if (
string.IsNullOrWhiteSpace(Jid))
6157 int SlashIndex = Jid.IndexOf(
'/');
6158 return SlashIndex > -1 ? Jid.Substring(0, SlashIndex) : Jid;
Contains information about a balance.
CaseInsensitiveString Currency
Currency of amount.
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 DecryptMessage(byte[] EncryptedMessage, byte[] PublicKey, Guid TransactionId, bool LocalIsRecipient)
Decrypts a message that was aimed at the client using the current keys.
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.
Wallet balance event arguments.
Event arguments for events where a client URL needs to be displayed when buying eDaler.
string ClientUrl
URL client needs to open to complete the transaction of buying eDaler.
string TransactionId
Transaction ID, if available in the response.
Event arguments for event signalling the completion of a payment operation.
decimal Amount
Amount paid
string Currency
Currency paid
string TransactionId
Transaction ID, if available in the response.
Event arguments for event signalling an error of a payment operation.
string TransactionId
Transaction ID, if available in the response.
new string Message
Error message.
Event arguments for operations returning payment options.
IDictionary< CaseInsensitiveString, object >[] Options
Payment options.
string TransactionId
Transaction ID, if available in the response.
Event arguments for events where a client URL needs to be displayed when selling eDaler.
string TransactionId
Transaction ID, if available in the response.
string ClientUrl
URL client needs to open to complete the transaction of 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
Represents an instance of the Neuro-Access app.
static new? App Current
Gets the current application instance.
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 string Provisioning
Provisioning channel
const string Petitions
Petitions channel
const string Identities
Identities channel
const string Messages
Messages channel
const string EDaler
eDaler channel
const string Tokens
Tokens channel
const string Contracts
Contracts channel
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
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.
A strongly-typed resource class, for looking up localized strings, etc.
static string UsernameNameAlreadyTaken
Looks up a localized string similar to Username already exists. Please try another....
static string InvalidUsernameOrPassword
Looks up a localized string similar to Invalid username or password.
static string NotificationPetitionContractTitle
Looks up a localized string similar to Contract request from {0}.
static string ControlServiceNotFound
Looks up a localized string similar to No control service found..
static string NeuroFeaturesServiceNotFound
Looks up a localized string similar to No Neuro-Features service found on the Service Provider....
static string NotificationIdentityRejectedBody
Looks up a localized string similar to Your identity was rejected..
static string NotificationPetitionSignatureBody
Looks up a localized string similar to A new signature request is waiting..
static string NotificationReadAccessBody
Looks up a localized string similar to Requested read access..
static string NotificationContractProposalTitle
Looks up a localized string similar to Contract proposal.
static string NotificationTokenRemovedBody
Looks up a localized string similar to Your wallet was updated..
static string DomainIsNotAValidOperator
Looks up a localized string similar to {0} is not a valid operator.
static string NotificationReadAccessTitle
Looks up a localized string similar to Read access request from {0}.
static string NotificationIdentityRejectedTitle
Looks up a localized string similar to Identity status updated.
static string NotificationContractProposalBody
Looks up a localized string similar to A contract proposal is available..
static string UnableToGetPresent
Looks up a localized string similar to Unable to get present report..
static string NotificationIdentityCompromisedBody
Looks up a localized string similar to Your identity may be compromised..
static string FileUploadServiceNotFound
Looks up a localized string similar to No file upload service found on the Service Provider....
static string PushNotificationServiceNotFound
Looks up a localized string similar to No push-notification service found..
static string UnableToGetListOfMyDevices
Looks up a localized string similar to Unable to get list of my devices..
static string NotificationTokenRemovedTitle
Looks up a localized string similar to Token removed.
static string NotificationIdentityObsoletedBody
Looks up a localized string similar to Your identity has been obsoleted..
static string PepServiceNotFound
Looks up a localized string similar to No personal eventing service found..
static string ProvisioningServiceNotFound
Looks up a localized string similar to No provisioning service found on the Service Provider....
static string NotificationBalanceUpdatedTitle
Looks up a localized string similar to Balance updated.
static string UnableToConnectTo
Looks up a localized string similar to Unable to connect to {0}.
static string NotificationPetitionIdentityBody
Looks up a localized string similar to A new identity request is waiting..
static string NotificationIdentityApprovedBody
Looks up a localized string similar to Your identity was approved..
static string UnableToGetStateDiagram
Looks up a localized string similar to Unable to get state diagram report..
static string NotificationControlAccessBody
Looks up a localized string similar to Requested control access..
static string NotificationContractUpdatedTitle
Looks up a localized string similar to Contract updated.
static string NotificationPetitionIdentityTitle
Looks up a localized string similar to Identity request from {0}.
static string OperatorDoesNotSupportRegisteringNewAccounts
Looks up a localized string similar to The operator {0} does not support registration of new accounts...
static string ThingRegistryServiceNotFound
Looks up a localized string similar to No thing registry service found on the Service Provider....
static string NotificationContractUpdatedBody
Looks up a localized string similar to A contract was updated..
static string ConcentratorServiceNotFound
Looks up a localized string similar to No concentrator service found..
static string NotificationContractSignedTitle
Looks up a localized string similar to Contract signed.
static string NotificationTokenAddedBody
Looks up a localized string similar to Your wallet was updated..
static string PubSubServiceNotFound
Looks up a localized string similar to Messaging service not available.
static string NotificationBalanceUpdatedBody
Looks up a localized string similar to Your balance was updated..
static string NotificationControlAccessTitle
Looks up a localized string similar to Control request from {0}.
static string NotificationIdentityApprovedTitle
Looks up a localized string similar to Identity status updated.
static string LegalServiceNotFound
Looks up a localized string similar to No legal service found on the Service Provider....
static string NotificationChatTitle
Looks up a localized string similar to {0}.
static string NotificationIdentityCompromisedTitle
Looks up a localized string similar to Identity status updated.
static string NotificationTokenAddedTitle
Looks up a localized string similar to Token added.
static string Ok
Looks up a localized string similar to OK.
static string UnableToGetProfiling
Looks up a localized string similar to Unable to get profiling report..
static string NotificationChatBody
Looks up a localized string similar to Has sent you a message..
static string UnableToAuthenticateWith
Looks up a localized string similar to Unable to authenticate with {0}.
static string SomethingWentWrong
Looks up a localized string similar to Something went wrong.
static string NotificationPresenceAccessBody
Looks up a localized string similar to Requested access to your identity..
static string EDalerServiceNotFound
Looks up a localized string similar to No eDaler service found on the Service Provider....
static string NotificationPetitionSignatureTitle
Looks up a localized string similar to Signature request from {0}.
static string UnableToGetHistory
Looks up a localized string similar to Unable to get history report..
static string NotificationPetitionContractBody
Looks up a localized string similar to A new contract request is waiting..
static string SensorServiceNotFound
Looks up a localized string similar to No sensor service found..
static string DomainDoesNotFollowEncryptionPolicy
Looks up a localized string similar to {0} does not follow the ubiquitous encryption policy.
static string NotificationPresenceAccessTitle
Looks up a localized string similar to Access request from {0}.
static string UnableToConnect
Looks up a localized string similar to Unable to connect..
static string NotificationIdentityObsoletedTitle
Looks up a localized string similar to Identity status updated.
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
static string NotificationContractSignedBody
Looks up a localized string similar to A contract was signed..
static string CantConnectTo
Looks up a localized string similar to Can't connect to {0}.
static string InvalidIoTDiscoClaimUri
Looks up a localized string similar to Not a valid iotdisco claim URI..
Contains a local reference to a contract that the user has created or signed.
async Task SetContract(Contract Contract)
Sets a parsed contract.
Contains additional data about an invalid claim.
Captures the result of an application review returned from backend services.
string? Code
Optional machine readable code identifying the review reason.
string Message
The localized or raw message describing the review result.
Contains additional data about an invalid photo.
Contains a local reference to a KYC process.
string? CreatedIdentityId
The legal ID of the created identity (if any).
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.
Represents a filter decision for notification handling.
static NotificationFilterDecision None
Gets a decision that does not ignore any operation.
Platform-neutral intent describing how to route a notification.
string? EntityId
Gets or sets an entity identifier associated with the action.
string? Channel
Gets or sets the push channel identifier.
Dictionary< string, string > Extras
Gets or sets extra data used for routing.
Base class that references services in the app.
static IServiceProvider Provider
The service provider for the app. This is set before the app is started, and will be used to resolve ...
static ILogService LogService
Log service.
static INetworkService NetworkService
Network service.
static IUiService UiService
Service serializing and managing UI-related tasks.
static INavigationService NavigationService
The navigation service for navigating between pages.
static IPopupService PopupService
Popup service for presenting application popups.
static ITagProfile TagProfile
TAG Profile service.
static ICryptoService CryptoService
Crypto service.
static IReportingStringLocalizer Localizer
Localization service
static IXmppService XmppService
The XMPP service for XMPP communication.
The view model to bind to for when displaying the applications page.
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
Orchestrates the interactive KYC flow, covering navigation, validation, summary projection,...
Navigation arguments for onboarding flow. Scenario determines dynamic starting step.
The data model for registering an identity.
Property[] ToProperties(IXmppService XmppService)
Converts the RegisterIdentityModel to an array of .
Event arguments events when the current state of a state-machine has changed.
Event arguments for report callback methods.
string ReportText
Markdown report.
Event arguments for token events.
Event arguments events when the variables of a state-machine has changed.
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.
Contains information about a response to a content request.
object Decoded
Decoded object.
void AssertOk()
Asserts response is OK.
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< ContentResponse > 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.
void Dispose()
IDisposable.Dispose()
virtual Task DisposeAsync()
IDisposableAsync.DisposeAsync()
Event sink sending events to a destination over the XMPP network.
const string NamespaceEventLogging
urn:xmpp:eventlog
Outputs sniffed data to Debug.
Sniffer that stores events in memory.
void Warning(string Warning)
Called to inform the viewer of a warning state.
void Error(string Error)
Called to inform the viewer of an error state.
void TransmitText(string Text)
Called when text has been transmitted.
void Information(string Comment)
Called to inform the viewer of something.
void ReceiveText(string Text)
Called when text has been received.
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
The authentication failed because the initiating entity did not provide proper credentials,...
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
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 PetitionContractAsync(string ContractId, string PetitionId, string Purpose)
Sends a petition to the parts of a smart contract, to access the information in the contract....
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< IdentityValidationEventArgs > ValidateAsync(LegalIdentity Identity)
Validates a legal identity.
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 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...
async Task EnableE2eEncryption()
Enables the keys of the Contracts Client to be used for End-to-End Encrypted communication over the X...
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.
async Task< LegalIdentity > UploadLegalIdAttachmentAsync(string LegalId, string FileName, byte[] Data, string ContentType)
Uploads an attachment to a Legal Identity application.
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.
Identity Review event arguments.
string Code
Machine-readable code corresponding to the first error message.
Event arguments for smart contract petitions
Event arguments for smart contract petition responses
string PetitionId
Petition ID
Event arguments for smart contract proposals
string ContractId
ID of proposed contract.
Event arguments for events referencing a contract.
string ContractId
ID of contract being signed.
Event arguments for contract signature events
Event arguments for identity validation responses
IdentityStatus Status
Validation status of legal identity.
Event arguments for legal identity responses
LegalIdentity Identity
Legal Identity
Event arguments for legal identity petitions
Event arguments for legal identity petition responses
string PetitionId
Petition ID
Event arguments for events where a client URL needs to be displayed when performing a petition.
string ClientUrl
URL client needs to open to complete the peer review.
string PetitionId
ID of peer review petition.
LegalIdentity RequestorIdentity
Legal Identity of requesting entity.
string RequestorFullJid
Full JID of requestor.
string PetitionId
Petition ID
Event arguments for digital signature petitions
Event arguments for signature petition responses
string PetitionId
Petition ID
Represents an invalidated claim.
string ReasonCode
A machine-readable code for the reason for invalidating the claim. (Each service can define its own r...
string ReasonLanguage
ISO code of language used for Reason.
string Claim
Identifier of claim
Represents an invalidated photo.
string ReasonCode
A machine-readable code for the reason for invalidating the photo. (Each service can define its own r...
string FileName
File name of Invalidated photo.
string ReasonLanguage
ISO code of language used for Reason.
DateTime Created
When the identity object was created
IdentityState State
Current state of identity
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(string 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.
Event arguments for responses to IQ queries.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppException StanzaError
Any stanza error returned.
Event arguments for message events.
string Id
ID attribute of message stanza.
string From
From where the message was received.
XmlElement Message
The message stanza.
string Body
Human readable body.
string FromBareJID
Bare JID of resource sending the message.
bool Ok
If the response is an OK result response (true), or an error response (false).
string To
To whom the message was sent.
XmlElement Content
Content of the message. For messages that are processed by registered message handlers,...
XmppException StanzaError
Any stanza error returned.
Event arguments for presence events.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmlElement Presence
Presence element.
string FromBareJID
Bare JID of resource sending the presence.
virtual string NickName
NickName, if available, as defined in XEP-0172. Can be sent in presence subscription requests,...
async Task Decline()
Declines a subscription or unsubscription request.
async Task Accept()
Accepts a subscription or unsubscription request.
XmppClient Client
XMPP Client. Is null if event raised by a component.
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
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.
PubSubClient PubSubClient
PubSubClient used for the Personal Eventing Protocol. Use this client to perform administrative tasks...
bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Unregisters an event handler of a specific type of personal events.
Event arguments for CanControl events.
Event arguments for CanRead events.
Event arguments for IsFriend 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.
Event arguments for items callback events.
PubSubItem[] Items
Items found.
ResultPage Page
Pagination information, if available, null otherwise.
Event arguments for node callback events.
Contains information about the configuration of a node.
Client managing communication with a Publish/Subscribe component. https://xmpp.org/extensions/xep-006...
Task DeleteNode(string Name, EventHandlerAsync< NodeEventArgs > Callback, object State)
Deletes a node.
Task GetLatestItems(string NodeName, int Count, EventHandlerAsync< ItemsEventArgs > Callback, object State)
Gets the latest items from a node.
Task PurgeNode(string Name, EventHandlerAsync< NodeEventArgs > Callback, object State)
Purges a node (deletes all items persisted on the node).
Task GetItems(string NodeName, EventHandlerAsync< ItemsEventArgs > Callback, object State)
Gets items from a node.
Task CreateNode(string Name, EventHandlerAsync< NodeEventArgs > Callback, object State)
Creates a node on the server.
Task Retract(string Node, string ItemId, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Retracts an item from a node.
const string NamespaceDelayedDelivery
urn:xmpp:delay (XEP-0203)
const string NamespacePubSub
http://jabber.org/protocol/pubsub
string ComponentAddress
Publish/Subscribe component address.
Task Subscribe(string NodeName, EventHandlerAsync< SubscriptionEventArgs > Callback, object State)
Subscribes to a node.
Task Unsubscribe(string NodeName, EventHandlerAsync< SubscriptionEventArgs > Callback, object State)
Unsubscribes from a node.
Task Publish(string Node, EventHandlerAsync< ItemResultEventArgs > Callback, object State)
Publishes an item on a node.
Represents a published item.
Contains options for a node subscription
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.
async Task ClearRulesAsync()
Clears available push notification rules for the client.
Class redirecting sniffer output to a remote client.
Contains information about a restricted query, as deinfed in XEP-0059: Result Set Management
Contains information about a result page, as deinfed in XEP-0059: Result Set Management
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.
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...
string[] Alternatives
Alternatives
The entity has attempted to send XML stanzas or other outbound data before the stream has been authen...
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.
Task SendMessage(MessageType Type, string To, string CustomXml, string Body, string Subject, string Language, string ThreadId, string ParentThreadId)
Sends a simple chat message
async Task DisposeAsync()
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...
Task SendServiceItemsDiscoveryRequest(string To, EventHandlerAsync< ServiceItemsDiscoveryEventArgs > Callback, object State)
Sends a service items discovery request
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 Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
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...
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 ApplyApplicationReviewAsync(KycReference Reference, ApplicationReview Review)
Persists review metadata from the provider.
Interface for the redesigned notification service.
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.
RegistrationStep Step
This profile's current registration step.
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.
void SetXmppPasswordNeedsUpdating(bool Value)
Sets the local flag for if xmpp password needs updating.
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? PubSubJid
The XMPP server's PubSub JID.
bool GetXmppPasswordNeedsUpdating()
Returns true if the current ITagProfile needs to have its Xmpp Password updated, false otherwise.
string BareJid
The Bare Jid of the current connection, or null.
Interface for asynchronously disposable objects.
Task DisposeAsync()
Disposes of the object, asynchronously.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Task Flush()
Persists any pending changes.
Interface for thing references.
NotificationAction
Actions that can be routed from notifications.
NotificationSource
Describes the source producing a notification.
RegistrationStep
The different steps of a TAG Profile registration journey.
class Photo(byte[] Binary, int Rotation, Attachment? Attachment)
Class containing information about a photo.
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.
class RegistrationPageMessage(RegistrationStep Step)
RegistrationPage view change message
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.
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
BinaryPresentationMethod
How binary data is to be presented.
ReportingReason
Reason for blocking.
IdentityState
Lists recognized legal identity states.
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.
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....