2using System.Collections.Generic;
3using System.Diagnostics;
6using System.Net.NetworkInformation;
7using System.Net.Security;
8using System.Net.Sockets;
9using System.Reflection;
10using System.Security.Cryptography;
11using System.Security.Cryptography.X509Certificates;
14using System.Threading;
15using System.Threading.Tasks;
230 private static readonly RandomNumberGenerator rnd = RandomNumberGenerator.Create();
231 private static readonly Dictionary<CaseInsensitiveString, S2SRec> remoteDomainLookup =
new Dictionary<CaseInsensitiveString, S2SRec>();
233 internal static readonly UTF8Encoding encoding =
new UTF8Encoding(
false,
false);
239 private readonly
SmtpServer smtpServer =
null;
240 private readonly
HttpServer httpServer =
null;
242 private LinkedList<TcpListener> c2sListeners =
new LinkedList<TcpListener>();
243 private LinkedList<TcpListener> s2sListeners =
new LinkedList<TcpListener>();
246 private readonly Dictionary<CaseInsensitiveString, List<IClientConnection>> connectionsPerBareJid =
new Dictionary<CaseInsensitiveString, List<IClientConnection>>();
247 private readonly Dictionary<string, EventHandlerAsync<IqEventArgs>> iqGetHandlers =
new Dictionary<string, EventHandlerAsync<IqEventArgs>>();
248 private readonly Dictionary<string, EventHandlerAsync<IqEventArgs>> iqSetHandlers =
new Dictionary<string, EventHandlerAsync<IqEventArgs>>();
249 private readonly Dictionary<string, EventHandlerAsync<MessageEventArgs>> messageHandlers =
new Dictionary<string, EventHandlerAsync<MessageEventArgs>>();
250 private readonly SortedDictionary<string, bool> features =
new SortedDictionary<string, bool>();
251 private readonly SortedDictionary<CaseInsensitiveString, IComponent> componentsBySubdomain =
new SortedDictionary<CaseInsensitiveString, IComponent>();
252 private readonly SortedDictionary<CaseInsensitiveString, IComponent> componentsByFulldomain =
new SortedDictionary<CaseInsensitiveString, IComponent>();
253 private readonly Dictionary<string, PendingRequest> pendingRequestsById =
new Dictionary<string, PendingRequest>();
254 private readonly SortedDictionary<DateTime, PendingRequest> pendingRequestsByTimeout =
new SortedDictionary<DateTime, PendingRequest>();
256 private readonly SortedDictionary<CaseInsensitiveString, S2sEndpointStatistics> s2sStatistics =
new SortedDictionary<CaseInsensitiveString, S2sEndpointStatistics>();
257 private Dictionary<string, Statistic> stanzasPerStanzaType =
new Dictionary<string, Statistic>();
258 private Dictionary<string, Statistic> stanzasPerFromDomain =
new Dictionary<string, Statistic>();
259 private Dictionary<string, Statistic> stanzasPerToDomain =
new Dictionary<string, Statistic>();
260 private Dictionary<string, Statistic> stanzasPerFromBareJid =
new Dictionary<string, Statistic>();
261 private Dictionary<string, Statistic> stanzasPerToBareJid =
new Dictionary<string, Statistic>();
262 private Dictionary<string, Statistic> stanzasPerNamespace =
new Dictionary<string, Statistic>();
263 private Dictionary<string, Statistic> stanzasPerFqn =
new Dictionary<string, Statistic>();
264 private readonly
object statSync =
new object();
265 private DateTime lastStat = DateTime.Now;
269 private SortedDictionary<DateTime, IS2SEndpoint> temporaryConnections =
null;
270 private X509Certificate serverCertificate;
273 private Timer secondTimer =
null;
274 private readonly
byte[] sha256DialbackSecret;
275 private readonly
object synchObject =
new object();
277 private readonly Random gen =
new Random();
280 private readonly
string serverName;
281 private readonly
string serverVersion;
282 private readonly
string serverOS;
283 private string domainSnifferPath =
null;
284 private string clientSnifferPath =
null;
285 private readonly
bool encryptionRequired;
286 private bool disposed =
false;
289 private readonly
int defaultRetryTimeout = 5000;
290 private readonly
int defaultNrRetries = 5;
291 private readonly
int defaultMaxRetryTimeout =
int.MaxValue;
292 private readonly
bool defaultDropOff =
true;
293 private long nrBytesRx = 0;
294 private long nrBytesTx = 0;
295 private long nrStanzas = 0;
301 Log.Terminating += (Sender, e) =>
355 PersistenceLayer,
null,
null);
376 if (mechanisms is
null)
383 Types.OnInvalidated += Types_OnInvalidated;
387 mechanisms = await GetMechanisms();
395 private static readonly
object synchObj =
new object();
396 private static bool first =
true;
398 private static async Task<IAuthenticationMechanism[]> GetMechanisms()
400 Dictionary<string, bool> MechanismsFound =
new Dictionary<string, bool>();
401 List<IAuthenticationMechanism> Result =
new List<IAuthenticationMechanism>();
418 if (MechanismsFound.ContainsKey(Mechanism.
Name))
419 throw new Exception(
"Authentication mechanism collision." + T.FullName +
": " + Mechanism.
Name);
423 MechanismsFound[Mechanism.
Name] =
true;
424 Result.Add(Mechanism);
432 Result.Sort((m1, m2) => m2.Weight - m1.Weight);
434 return Result.ToArray();
437 private static async
void Types_OnInvalidated(
object Sender, EventArgs e)
441 mechanisms = await GetMechanisms();
466 this.persistenceLayer = PersistenceLayer;
481 throw new ArgumentException(
"Server Certificate must be provided, if encryption is required.", nameof(
ServerCertificate));
484 this.clientConnections.Removed += this.ClientConnections_Removed;
487 this.s2sEndpoints.Removed += this.S2sEndpoints_Removed;
489 Assembly ThisAssembly = typeof(
XmppServer).Assembly;
490 StackTrace Trace =
new StackTrace();
491 StackFrame[] Frames = Trace.GetFrames();
496 int c = Frames.Length;
501 Method = Frame.GetMethod();
502 Assembly = Method.DeclaringType.Assembly;
504 while (Assembly == ThisAssembly);
506 AssemblyName Name = Assembly.GetName();
507 string Title =
string.Empty;
508 string Product =
string.Empty;
509 string AssemblyName = Name.Name;
511 foreach (
object Attribute
in Assembly.GetCustomAttributes())
513 if (Attribute is AssemblyTitleAttribute AssemblyTitleAttribute)
514 Title = AssemblyTitleAttribute.Title;
515 else if (Attribute is AssemblyProductAttribute AssemblyProductAttribute)
516 Product = AssemblyProductAttribute.Product;
519 if (!
string.IsNullOrEmpty(Title))
520 this.serverName = Title;
521 else if (!
string.IsNullOrEmpty(Product))
522 this.serverName = Product;
524 this.serverName = AssemblyName;
526 this.serverVersion = Name.Version.ToString();
527 this.serverOS = Environment.OSVersion.ToString();
533 this.
RegisterIqGetHandler(
"query", PrivateXmlStorageNamespace, this.PrivateXmlStorageGet,
true);
534 this.
RegisterIqSetHandler(
"query", PrivateXmlStorageNamespace, this.PrivateXmlStorageSet,
false);
558 this.Initialize(ClientToServerPorts, ServerToServerPorts);
561 private async
void Initialize(
int[] ClientToServerPorts,
int[] ServerToServerPorts)
565 TcpListener Listener;
567 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
569 if (Interface.OperationalStatus != OperationalStatus.Up)
572 IPInterfaceProperties
Properties = Interface.GetIPProperties();
574 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
576 if ((UnicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && Socket.OSSupportsIPv4) ||
577 (UnicastAddress.Address.AddressFamily == AddressFamily.InterNetworkV6 && Socket.OSSupportsIPv6))
579 if (!(ClientToServerPorts is
null))
581 foreach (
int C2sPort
in ClientToServerPorts)
585 await this.c2sSniffers.Information(
"Opening port " + C2sPort.ToString() +
" on " + UnicastAddress.Address.ToString() +
".");
587 Listener =
new TcpListener(UnicastAddress.Address, C2sPort);
589 Listener.BeginAcceptTcpClient(this.AcceptTcpClientCallback,
new object[] { Listener,
false });
590 this.c2sListeners.AddLast(Listener);
592 await this.c2sSniffers.Information(
"Port " + C2sPort.ToString() +
" on " + UnicastAddress.Address.ToString() +
" opened.");
596 Log.
Exception(ex, UnicastAddress.Address.ToString() +
":" + C2sPort);
601 if (!(ServerToServerPorts is
null))
603 foreach (
int S2sPort
in ServerToServerPorts)
607 await this.s2sSniffers.Information(
"Opening port " + S2sPort.ToString() +
" on " + UnicastAddress.Address.ToString() +
".");
609 Listener =
new TcpListener(UnicastAddress.Address, S2sPort);
611 Listener.BeginAcceptTcpClient(this.AcceptTcpClientCallback,
new object[] { Listener,
true });
612 this.s2sListeners.AddLast(Listener);
614 await this.s2sSniffers.Information(
"Port " + S2sPort.ToString() +
" on " + UnicastAddress.Address.ToString() +
" opened.");
618 Log.
Exception(ex, UnicastAddress.Address.ToString() +
":" + S2sPort);
626 this.secondTimer =
new Timer(this.SecondTimerCallback,
null, 1000, 1000);
628 if (!(this.smtpServer is
null))
629 this.smtpServer.MessageReceived += this.SmtpServer_MessageReceived;
674 byte[] Result =
new byte[NrBytes];
678 rnd.GetBytes(Result);
696 this.ConnectionClosed(e.
Value);
699 await e.
Value.DisposeAsync();
710 lock (this.s2sStatistics)
712 return this.s2sStatistics.TryGetValue(Endpoint, out Stat);
726 lock (this.s2sStatistics)
728 if (!this.s2sStatistics.TryGetValue(Endpoint, out Result))
731 this.s2sStatistics[Endpoint] = Result;
738 internal void S2sEndpointDisposed(
IS2SEndpoint Endpoint)
742 if (!(this.s2sEndpoints is
null) && !(Endpoint is
null) && !
string.IsNullOrEmpty(
Domain) &&
752 new KeyValuePair<string, object>(
"Reason", e.
Reason));
758 XmppS2SEndpoint.OnStateChanged -= this.Endpoint_OnStateChanged;
760 await e.
Value.DisposeAsync();
773 return this.s2sEndpoints.
GetKeys();
782 get => this.clientConnections.
Count;
793 Array.Sort(Connections, (c1, c2) =>
809 return this.clientConnections.
TryGetValue(FullJID, out Connection);
820 lock (this.connectionsPerBareJid)
822 if (this.connectionsPerBareJid.TryGetValue(BareJID, out List<IClientConnection> Connections2))
824 Connections = Connections2.ToArray();
838 get => this.s2sEndpoints.
Count;
847 lock (this.s2sStatistics)
850 this.s2sStatistics.Values.CopyTo(Result, 0);
863 if (
Domain == this.domain)
866 if (IncludeAlternativeDomains)
891 get => this.alternativeDomains;
899 get => this.serverCertificate;
916 get => this.encryptionRequired;
925 get => this.domainSnifferPath;
926 set => this.domainSnifferPath = value;
935 get => this.clientSnifferPath;
936 set => this.clientSnifferPath = value;
941 get => this.persistenceLayer;
949 this.disposed =
true;
951 if (!(this.httpServer is
null))
953 this.httpServer.Unregister(this.requestWhiteList);
954 this.requestWhiteList =
null;
957 if (!(this.smtpServer is
null))
958 this.smtpServer.MessageReceived -= this.SmtpServer_MessageReceived;
960 this.secondTimer?.Dispose();
961 this.secondTimer =
null;
963 if (!(this.s2sEndpoints is
null))
965 this.s2sEndpoints.
Clear();
967 this.s2sEndpoints =
null;
970 if (!(this.clientConnections is
null))
972 this.clientConnections.
Clear();
973 this.clientConnections.
Dispose();
974 this.clientConnections =
null;
977 if (!(this.sniffers is
null))
979 this.sniffers.
Clear();
981 this.sniffers =
null;
984 if (!(this.componentsBySubdomain is
null))
989 this.componentsBySubdomain.Clear();
990 this.componentsByFulldomain.Clear();
995 this.accounts =
null;
998 this.services =
null;
1000 this.responses.Dispose();
1002 if (!(this.c2sListeners is
null))
1004 LinkedList<TcpListener> Listeners = this.c2sListeners;
1005 this.c2sListeners =
null;
1007 foreach (TcpListener Listener
in Listeners)
1011 if (!(this.s2sListeners is
null))
1013 LinkedList<TcpListener> Listeners = this.s2sListeners;
1014 this.s2sListeners =
null;
1016 foreach (TcpListener Listener
in Listeners)
1020 if (!(this.c2sSniffers is
null))
1022 foreach (
ISniffer Sniffer
in this.c2sSniffers)
1023 (Sniffer as IDisposable)?.
Dispose();
1026 if (!(this.s2sSniffers is
null))
1028 foreach (
ISniffer Sniffer
in this.s2sSniffers)
1029 (Sniffer as IDisposable)?.
Dispose();
1045 return this.GetOpenPorts(this.c2sListeners);
1056 return this.GetOpenPorts(this.s2sListeners);
1065 private int[] GetOpenPorts(LinkedList<TcpListener> Listeners)
1067 SortedDictionary<int, bool> Open =
new SortedDictionary<int, bool>();
1069 if (!(Listeners is
null))
1071 IPEndPoint IPEndPoint;
1073 foreach (TcpListener Listener
in Listeners)
1075 IPEndPoint = Listener.LocalEndpoint as IPEndPoint;
1076 if (!(IPEndPoint is
null))
1077 Open[IPEndPoint.Port] =
true;
1081 int[] Result =
new int[Open.Count];
1082 Open.Keys.CopyTo(Result, 0);
1098 lock (this.synchObject)
1104 this.componentsByFulldomain[Component.Subdomain +
"." + this.domain] =
Component;
1107 this.componentsByFulldomain[Component.Subdomain +
"." + cis] =
Component;
1109 this.RebuildComponentsStaticLocked();
1115 private void RebuildComponentsStaticLocked()
1118 this.componentsBySubdomain.Values.CopyTo(Static, 0);
1120 this.componentsStatic = Static;
1130 bool Result =
false;
1132 lock (this.synchObject)
1146 this.RebuildComponentsStaticLocked();
1158 private async
void AcceptTcpClientCallback(IAsyncResult ar)
1162 if (this.disposed ||
1163 !(ar?.AsyncState is
object[] P) ||
1165 !(P[0] is TcpListener Listener) ||
1166 !(P[1] is
bool S2S) ||
1174 TcpClient Client = Listener.EndAcceptTcpClient(ar);
1188 if (!
string.IsNullOrEmpty(this.clientSnifferPath))
1190 else if (this.c2sSniffers.HasSniffers)
1191 Sniffers = this.c2sSniffers.Sniffers;
1200 await ComLayer.
Information(
"Connection accepted from " + Client.Client?.RemoteEndPoint?.ToString() +
".");
1205 Listener.BeginAcceptTcpClient(this.AcceptTcpClientCallback, P);
1208 catch (SocketException)
1212 catch (ObjectDisposedException)
1216 catch (NullReferenceException)
1220 catch (Exception ex)
1222 if (this.c2sListeners is
null)
1229 internal string GetTransformPath(
bool S2S)
1231 foreach (
ISniffer Sniffer
in S2S ? this.s2sSniffers.Sniffers :
this.c2sSniffers.Sniffers)
1248 public string GetDialbackKey(
string ReceivingServer,
string OriginatingServer,
string ReceivingStreamId)
1250 StringBuilder sb =
new StringBuilder();
1252 sb.Append(ReceivingServer);
1254 sb.Append(OriginatingServer);
1256 sb.Append(ReceivingStreamId);
1258 byte[] Bin = Encoding.UTF8.GetBytes(sb.ToString());
1275 return this.persistenceLayer.GetAccount(UserName);
1286 return this.clientConnections.
TryGetValue(FullJid, out Connection);
1296 return this.clientConnections?.
ContainsKey(FullJid) ??
false;
1319 if (!Connection2.CheckLive())
1320 this.clientConnections.
Remove(FullJid);
1325 this.clientConnections[FullJid] = Connection;
1329 lock (this.connectionsPerBareJid)
1331 if (!this.connectionsPerBareJid.TryGetValue(BareJid, out List<IClientConnection> Connections))
1333 Connections =
new List<IClientConnection>();
1334 this.connectionsPerBareJid[BareJid] = Connections;
1337 Connections.Add(Connection);
1387 FullJid = BareJid +
"/" + this.
NewId(16);
1389 while (!this.disposed && this.clientConnections.
ContainsKey(FullJid));
1393 this.clientConnections[FullJid] = Connection;
1395 lock (this.connectionsPerBareJid)
1397 if (!this.connectionsPerBareJid.TryGetValue(BareJid, out List<IClientConnection> Connections))
1399 Connections =
new List<IClientConnection>();
1400 this.connectionsPerBareJid[BareJid] = Connections;
1403 Connections.Add(Connection);
1421 this.clientConnections?.
Remove(FullJid);
1423 lock (this.connectionsPerBareJid)
1425 if (this.connectionsPerBareJid.TryGetValue(BareJid, out List<IClientConnection> Connections))
1427 int i, c = Connections.Count;
1429 for (i = 0; i < c; i++)
1431 if (Connections[i].FullJid == FullJid)
1433 Connections.RemoveAt(i);
1437 this.connectionsPerBareJid.Remove(BareJid);
1448 lock (this.connectionsPerBareJid)
1450 if (this.connectionsPerBareJid.TryGetValue(BareJid, out List<IClientConnection> Connections))
1451 return Connections.ToArray();
1478 if (Connection is
null)
1483 if (Auditor is
null)
1484 return Task.FromResult<DateTime?>(
null);
1489 internal async Task<bool> Authenticate(
string Mechanism, SslStream SslStream,
IClientConnection Connection,
string Data)
1495 StringBuilder sb =
new StringBuilder();
1496 DateTime TP = Next.Value;
1497 DateTime Today = DateTime.Today;
1499 if (Next.Value == DateTime.MaxValue)
1501 sb.Append(
"This endpoint (");
1503 sb.Append(
") has been blocked from the system.");
1507 sb.Append(
"Too many failed login attempts in a row registered. Try again after ");
1508 sb.Append(TP.ToLongTimeString());
1510 if (TP.Date != Today)
1512 if (TP.Date == Today.AddDays(1))
1513 sb.Append(
" tomorrow");
1517 sb.Append(TP.ToShortDateString());
1521 sb.Append(
". Remote Endpoint: ");
1532 if (M.
Name == Mechanism)
1543 if (AuthResult.HasValue)
1545 if (AuthResult.Value)
1554 catch (Exception ex)
1585 return new Tuple<bool, IRecipient>(
false,
null);
1588 return new Tuple<bool, IRecipient>(
true,
this);
1591 return new Tuple<bool, IRecipient>(
true, Connection);
1596 return new Tuple<bool, IRecipient>(
false,
null);
1600 IAccount Account = await this.persistenceLayer.GetAccount(To.
Account);
1601 if (Account is
null)
1602 return new Tuple<bool, IRecipient>(
false,
null);
1604 return new Tuple<bool, IRecipient>(
true,
new AccountRecipient(this.accounts, Account));
1610 lock (this.synchObject)
1612 if (!this.componentsByFulldomain.TryGetValue(To.
Domain, out
Component))
1619 return new Tuple<bool, IRecipient>(
true,
Component);
1621 return new Tuple<bool, IRecipient>(
false,
null);
1626 IS2SEndpoint Endpoint = await this.GetS2sEndpoint(From.
Domain, To.
Domain,
true, From +
" wants to send a stanza to " + To);
1628 return new Tuple<bool, IRecipient>(!(Endpoint is
null), Endpoint);
1632 return new Tuple<bool, IRecipient>(
false,
null);
1647 public void RegisterIqGetHandler(
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
bool PublishNamespaceAsFeature)
1649 this.RegisterIqHandler(this.iqGetHandlers, LocalName, Namespace, Handler, PublishNamespaceAsFeature);
1659 public void RegisterIqSetHandler(
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
bool PublishNamespaceAsFeature)
1661 this.RegisterIqHandler(this.iqSetHandlers, LocalName, Namespace, Handler, PublishNamespaceAsFeature);
1664 private void RegisterIqHandler(Dictionary<
string, EventHandlerAsync<IqEventArgs>> Handlers,
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
1665 bool PublishNamespaceAsFeature)
1667 string Key = LocalName +
" " + Namespace;
1669 lock (this.synchObject)
1671 if (Handlers.ContainsKey(Key))
1672 throw new ArgumentException(
"Handler already registered.", nameof(LocalName));
1674 Handlers[Key] = Handler;
1676 if (PublishNamespaceAsFeature)
1677 this.features[Namespace] =
true;
1688 public void RegisterMessageHandler(
string LocalName,
string Namespace, EventHandlerAsync<MessageEventArgs> Handler,
bool PublishNamespaceAsFeature)
1690 string Key = LocalName +
" " + Namespace;
1692 lock (this.synchObject)
1694 if (this.messageHandlers.ContainsKey(Key))
1695 throw new ArgumentException(
"Handler already registered.", nameof(LocalName));
1697 this.messageHandlers[Key] = Handler;
1699 if (PublishNamespaceAsFeature)
1700 this.features[Namespace] =
true;
1712 public bool UnregisterIqGetHandler(
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
bool RemoveNamespaceAsFeature)
1714 return this.UnregisterIqHandler(this.iqGetHandlers, LocalName, Namespace, Handler, RemoveNamespaceAsFeature);
1725 public bool UnregisterIqSetHandler(
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
bool RemoveNamespaceAsFeature)
1727 return this.UnregisterIqHandler(this.iqSetHandlers, LocalName, Namespace, Handler, RemoveNamespaceAsFeature);
1730 private bool UnregisterIqHandler(Dictionary<
string, EventHandlerAsync<IqEventArgs>> Handlers,
string LocalName,
string Namespace, EventHandlerAsync<IqEventArgs> Handler,
1731 bool RemoveNamespaceAsFeature)
1733 string Key = LocalName +
" " + Namespace;
1735 lock (this.synchObject)
1737 if (!Handlers.TryGetValue(Key, out EventHandlerAsync<IqEventArgs> h))
1743 Handlers.Remove(Key);
1745 if (RemoveNamespaceAsFeature)
1746 this.features.Remove(Namespace);
1760 public bool UnregisterMessageHandler(
string LocalName,
string Namespace, EventHandlerAsync<MessageEventArgs> Handler,
bool RemoveNamespaceAsFeature)
1762 string Key = LocalName +
" " + Namespace;
1764 lock (this.synchObject)
1766 if (!this.messageHandlers.TryGetValue(Key, out EventHandlerAsync<MessageEventArgs> h))
1772 this.messageHandlers.Remove(Key);
1774 if (RemoveNamespaceAsFeature)
1775 this.features.Remove(Namespace);
1790 return !(await Sender.IqErrorItemNotFound(Id, From, To,
"Recipient not found: " + To.
Address,
"en") is
null);
1793 await this.persistenceLayer.IsBlocked(From.
BareJid, ToConnection.BareJid))
1795 return !(await Sender.IqErrorServiceUnavailable(Id, From, To,
string.Empty,
string.Empty) is
null);
1798 return await Recipient.IQ(Type, Id, To, From, Language,
Stanza, Sender);
1813 Dictionary<string, EventHandlerAsync<IqEventArgs>> Handlers;
1814 EventHandlerAsync<IqEventArgs> h =
null;
1816 bool Blocked = await this.persistenceLayer.IsBlocked(From.
BareJid, To.
BareJid);
1821 if (this.responses.TryGet(From.
Address, Id, out
string ResponseXml, out
bool Ok))
1824 return await Sender.
IqResult(Id, From, To, ResponseXml);
1826 return await Sender.
IqError(Id, From, To, ResponseXml);
1829 Handlers = this.iqGetHandlers;
1833 if (this.responses.TryGet(From.
Address, Id, out ResponseXml, out Ok))
1836 return await Sender.
IqResult(Id, From, To, ResponseXml);
1838 return await Sender.
IqError(Id, From, To, ResponseXml);
1841 Handlers = this.iqSetHandlers;
1849 return await this.ProcessResponse(Type, Id, To, From, Language,
true,
false,
Stanza, Sender);
1855 return !(await Sender.IqErrorBadRequest(Id, From, To,
"Invalid type.",
"en") is
null);
1863 return !(await Sender.IqErrorServiceUnavailable(Id, From, To,
string.Empty,
string.Empty) is
null);
1869 lock (this.synchObject)
1873 if (!(N is XmlElement E))
1876 Key = E.LocalName +
" " + E.NamespaceURI;
1877 if (Handlers.TryGetValue(Key, out h))
1889 return !(await Sender.
IqError(Id, From, To,
"cancel",
"<feature-not-implemented xmlns='" +
StanzaNamespace +
"'/>",
1890 string.Empty,
string.Empty) is
null);
1899 catch (Exception ex)
1904 return !(await Sender.
IqError(Id, From, To, ex) is
null);
1910 internal async Task<bool> ProcessResponse(
string Type,
string Id,
XmppAddress To,
XmppAddress From,
string Language,
1913 if (!
string.IsNullOrEmpty(Id))
1915 PendingRequest Rec =
null;
1916 bool Ok = (Type ==
"result");
1918 lock (this.synchObject)
1920 if (this.pendingRequestsById.TryGetValue(Id, out Rec))
1922 this.pendingRequestsById.Remove(Id);
1923 this.pendingRequestsByTimeout.Remove(Rec.Timeout);
1934 if (PresenceResponse)
1935 await Rec.PresenceCallback.Raise(
this,
new PresenceEventArgs(Sender, Type, Id, To, From, Language,
Stanza, Rec.State));
1954 return this.
IQ(Type, Id, To, From, Language, ToStanza(
"iq", Type, Id, To, From, Language, ContentXml), Sender);
1957 internal static Stanza ToStanza(
string StanzaType,
string Type,
string Id,
XmppAddress To,
XmppAddress From,
string Language,
string ContentXml)
1959 StringBuilder Xml =
new StringBuilder();
1960 StringBuilder Xml2 =
new StringBuilder();
1961 int ContentStart, ContentLen;
1963 Xml.Append(
"<stream:stream to='");
1965 Xml.Append(
"' from='");
1967 Xml.Append(
"' version='1.0' xml:lang='");
1969 Xml.Append(
"' xmlns='jabber:server' xmlns:stream='");
1974 Xml2.Append(StanzaType);
1976 if (!
string.IsNullOrEmpty(Type))
1978 Xml2.Append(
" type='");
1983 if (!
string.IsNullOrEmpty(Id))
1985 Xml2.Append(
" id='");
1992 Xml2.Append(
" from='");
1999 Xml2.Append(
" to='");
2004 if (!
string.IsNullOrEmpty(Language))
2006 Xml2.Append(
" xml:lang='");
2011 if (
string.IsNullOrEmpty(ContentXml))
2014 ContentStart = ContentLen = 0;
2020 ContentStart = Xml2.Length;
2021 ContentLen = ContentXml.Length;
2023 Xml2.Append(ContentXml);
2025 Xml2.Append(StanzaType);
2029 string s = Xml2.ToString();
2032 Xml.Append(
"</stream:stream>");
2036 XmlDocument Doc =
new XmlDocument()
2038 PreserveWhitespace =
true
2040 Doc.LoadXml(Xml.ToString());
2042 return new Stanza(Doc.DocumentElement, s, ContentStart, ContentLen);
2044 catch (Exception ex)
2046 throw new Exception(
"Invalid XML:\r\n\r\n" + ex.Message +
"\r\n\r\n" + Xml.ToString());
2066 if (await this.persistenceLayer.IsBlocked(From.
BareJid, To.
BareJid))
2067 return await (Sender?.MessageErrorServiceUnavailable(From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2068 else if (await this.persistenceLayer.IsBlocked(To.
BareJid, From.
BareJid))
2070 return await Sender.
Message(
"error", Id, From, To,
string.Empty,
"<error type='cancel'><not-acceptable xmlns='" +
StanzaNamespace +
2079 if (!(Connections is
null) && Connections.Length > 0)
2081 bool Forwarded =
false;
2087 if (await Connection.
Message(Type, Id, To, From, Language,
Stanza, Sender))
2090 catch (Exception ex)
2097 catch (Exception ex2)
2108 if (
string.IsNullOrEmpty(Type) || Type ==
"normal" || Type ==
"chat")
2110 if (await this.persistenceLayer.StoreOfflineMessage(Type, Id, To, From, Language,
Stanza))
2113 await ComLayer.Information(
"Message stored for later delivery.");
2116 return await (Sender?.MessageErrorServiceUnavailable(From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2123 bool Forwarded =
false;
2127 Forwarded = await Connection.Message(Type, Id, To, From, Language,
Stanza, Sender);
2129 catch (Exception ex)
2131 await Connection.Exception(ex);
2132 await Connection.DisposeAsync();
2139 return await (Sender?.MessageErrorServiceUnavailable(From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2149 lock (this.synchObject)
2151 if (!this.componentsByFulldomain.TryGetValue(To.
Domain, out
Component))
2165 Endpoint = await this.GetS2sEndpoint(From.
Domain, To.
Domain,
true,
"Sending message from " + From.
Address +
" to " + To.
Address);
2166 if (Endpoint is
null)
2169 catch (Exception ex)
2171 if (!(Sender is
null))
2172 return await (Sender?.MessageErrorServiceUnavailable(From, To, ex.Message,
string.
Empty) ?? Task.FromResult(
true));
2177 return await Endpoint.
Message(Type, Id, To, From, Language,
Stanza, Sender);
2191 lock (remoteDomainLookup)
2193 remoteDomainLookup[RemoteDomain] =
new S2SRec()
2198 TrustCertificate = TrustCertificate
2214 lock (remoteDomainLookup)
2216 remoteDomainLookup[RemoteDomain] =
new S2SRec()
2221 TrustCertificate = TrustCertificate
2226 internal async
void RegisterS2SEndpoint(
IS2SEndpoint Endpoint)
2230 EventHandlerAsync<ServerConnectionEventArgs> h;
2239 this.s2sEndpoints[
Domain] = Endpoint;
2244 XmppS2SEndpoint.OnStateChanged += this.Endpoint_OnStateChanged;
2247 private async Task Endpoint_OnStateChanged(
object Sender, EventArgs e)
2261 return this.s2sEndpoints.
TryGetValue(RemoteDomain, out Endpoint);
2264 internal void RegisterAsTemporary(
IS2SEndpoint Endpoint)
2266 lock (this.synchObject)
2268 if (this.temporaryConnections is
null)
2269 this.temporaryConnections =
new SortedDictionary<DateTime, IS2SEndpoint>();
2271 DateTime TP = DateTime.Now.AddMinutes(1);
2273 while (this.temporaryConnections.ContainsKey(TP))
2274 TP = TP.AddTicks(this.gen.Next(10));
2276 this.temporaryConnections[TP] = Endpoint;
2289 SrvMsg =
"Unable to get SRV record for xmpp-server/tcp of " + DomainName;
2292 Result =
new S2SRec()
2297 TrustCertificate =
false,
2304 catch (Exception ex)
2306 SrvMsg = ex.Message;
2312 if (Hosts.Length > 0 && !
string.IsNullOrEmpty(Hosts[0]))
2316 using (TcpClient TestClient =
new TcpClient())
2320 Log.
Notice(
"Federated XMPP server connection. SRV DNS settings not found: " + SrvMsg, DomainName);
2322 Result =
new S2SRec()
2327 TrustCertificate =
false,
2339 Log.
Notice(
"Federated mail server connection. XMPP server not found: " + SrvMsg, DomainName);
2341 Result =
new S2SRec()
2346 TrustCertificate =
false,
2370 lock (remoteDomainLookup)
2372 if (remoteDomainLookup.TryGetValue(DomainOrSubdomain, out Result))
2376 Result = await GetDomainFromDns(DomainOrSubdomain);
2377 if (!(Result is
null))
2380 Result.Domain = Result.
Host;
2382 lock (remoteDomainLookup)
2384 remoteDomainLookup[DomainOrSubdomain] = Result;
2392 throw new Exception(
"Invalid domain or subdomain name: " + DomainOrSubdomain);
2403 if (
Domain != DomainOrSubdomain)
2405 Rec = await GetDomainFromDns(
Domain);
2414 IPHostEntry Entry = await System.Net.Dns.GetHostEntryAsync(
Domain);
2415 if (Entry.AddressList.Length > 0)
2417 using (TcpClient TestClient =
new TcpClient())
2423 Result = Rec =
new S2SRec()
2429 TrustCertificate =
false
2443 if (Rec is
null && !(Result is
null) && Result.
Type ==
S2sType.XMPP)
2447 if (!(Result is
null))
2449 lock (remoteDomainLookup)
2451 remoteDomainLookup[DomainOrSubdomain] = Result;
2457 throw new Exception(
"Invalid S2S domain or subdomain name: " + DomainOrSubdomain);
2515 bool TrustCertificate;
2520 lock (remoteDomainLookup)
2522 RecFound = remoteDomainLookup.TryGetValue(RemoteDomain, out Rec);
2528 RemoteDomain = Rec.
Domain;
2542 this.s2sEndpoints.
Remove(RemoteDomain);
2543 await Endpoint.DisposeAsync();
2555 throw new NotSupportedException(
"S2S connections not supported. No domain defined.");
2556 else if (this.serverCertificate is
null)
2557 throw new NotSupportedException(
"S2S connections not supported. No server certificate defined.");
2559 Log.
Informational(
"Opening S2S connection. " + Reason, RemoteDomain,
string.Empty,
"XmppOpenS2s");
2563 int i = LocalDomain.
IndexOf(
'.');
2575 this.AddS2SSniffers(Result, RemoteDomain);
2583 if (this.smtpServer is
null)
2584 throw new NotSupportedException(
"Integration with SMTP not enabled.");
2586 Result =
new SmtpS2SEndpoint(LocalDomain, RemoteDomain, this.smtpServer,
this);
2590 throw new NotSupportedException(
"S2S Connection type not supported: " + Type.ToString());
2594 this.RegisterS2SEndpoint(Result);
2596 this.RegisterAsTemporary(Result);
2603 if (!
string.IsNullOrEmpty(this.domainSnifferPath))
2604 Endpoint.
Add(this.GetSniffer(RemoteDomain,
true));
2605 else if (this.s2sSniffers.HasSniffers)
2607 foreach (
ISniffer Sniffer
in this.s2sSniffers.Sniffers)
2608 Endpoint.
Add(Sniffer);
2614 lock (remoteDomainLookup)
2616 if (remoteDomainLookup.TryGetValue(RemoteDomain, out S2SRec Rec))
2617 return Rec.TrustCertificate;
2635 return this.
Message(Type, Id, To, From, Language, ToStanza(
"message", Type, Id, To, From, Language, ContentXml), Sender);
2656 case "unsubscribed":
2657 return await (Sender?.PresenceErrorNotAllowed(Id, From, this.domainAddress,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2661 IAccount FromAccount = await this.persistenceLayer.GetAccount(FromUserName);
2664 await this.PushPresence(FromConnection.BareAddress, Type, Id, From, Language,
Stanza,
false, Sender);
2666 foreach (
IRosterItem Item in await this.persistenceLayer.GetRoster(FromUserName))
2668 if (
Item.BareJid != FromConnection.BareJid &&
2671 await this.PushPresence(
new XmppAddress(
Item.BareJid), Type, Id, From, Language,
Stanza,
false, Sender);
2694 IAccount ToAccount = ToLocal ? await this.persistenceLayer.GetAccount(To.
Account) :
null;
2697 bool FromLocal = !(FromConnection is
null);
2701 bool UseBareJids =
false;
2703 if (!
string.IsNullOrEmpty(Id))
2705 PendingRequest Rec =
null;
2706 bool Ok = (Type !=
"error");
2708 lock (this.synchObject)
2710 if (this.pendingRequestsById.TryGetValue(Id, out Rec))
2712 this.pendingRequestsById.Remove(Id);
2713 this.pendingRequestsByTimeout.Remove(Rec.Timeout);
2719 if (!(Rec?.PresenceCallback is
null))
2720 await Rec.PresenceCallback.Raise(
this,
new PresenceEventArgs(Sender, Type, Id, To, From, Language,
Stanza, Rec.State));
2723 if (ToLocal && ToAccount is
null)
2724 return await (Sender?.PresenceErrorItemNotFound(Id, From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2728 FromUserName = FromConnection.
UserName;
2729 FromAccount = await this.persistenceLayer.GetAccount(FromUserName);
2731 if (FromAccount is
null)
2732 return await (Sender?.PresenceErrorNotAllowed(Id, From, this.domainAddress,
string.Empty,
string.Empty) ?? Task.FromResult(
true));
2740 if (await this.persistenceLayer.IsBlocked(From.
BareJid, To.
BareJid))
2743 Item = await this.persistenceLayer.GetRosterItem(FromUserName, To.
BareJid);
2745 if (!(
Item is
null))
2747 if (!
Item.PendingSubscription)
2753 if (!(
Item is
null))
2765 if (!(
Item is
null))
2770 false,
Item.Groups);
2775 false,
Item.Groups);
2780 if (!(
Item is
null))
2789 Item = await this.persistenceLayer.GetRosterItem(FromUserName, To.
BareJid);
2790 if (!(
Item is
null))
2795 Item.PendingSubscription,
Item.Groups);
2800 Item.PendingSubscription,
Item.Groups);
2808 if (!(
Item is
null))
2817 case "unsubscribed":
2822 if (!(
Item is
null))
2827 false,
Item.Groups);
2832 false,
Item.Groups);
2834 else if (
Item.PendingSubscription)
2837 false,
Item.Groups);
2842 if (!(
Item is
null))
2849 Item = await this.persistenceLayer.GetRosterItem(FromUserName, To.
BareJid);
2850 if (!(
Item is
null))
2855 Item.PendingSubscription,
Item.Groups);
2860 Item.PendingSubscription,
Item.Groups);
2865 if (!(
Item is
null))
2878 if (!(
Item is
null))
2883 false,
Item.Groups);
2888 false,
Item.Groups);
2893 if (!(
Item is
null))
2902 Item = await this.persistenceLayer.GetRosterItem(FromUserName, To.
BareJid);
2903 if (!(
Item is
null))
2908 false,
Item.Groups);
2913 false,
Item.Groups);
2915 else if (
Item.PendingSubscription)
2918 false,
Item.Groups);
2923 if (!(
Item is
null))
2928 await this.PushPresence(To, Type, Id, From.
ToBareJID(), Language,
Stanza, UseBareJids, Sender);
2930 Type =
"unavailable";
2939 if (ToAccount is
null ||
2940 await this.persistenceLayer.IsBlocked(From.
BareJid, To.
BareJid) ||
2942 (
Item = await
this.persistenceLayer.GetRosterItem(To.
Account, From.
BareJid)) is
null ||
2945 if (!await (Sender?.
Presence(
"unsubscribed", Id, From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true)))
2955 if (!(Connections is
null))
2974 LastPresence = Connection.LastPresence;
2980 if (!Sent && !await (Sender?.
Presence(
"unavailable", Id, From, To,
string.Empty,
string.Empty) ?? Task.FromResult(
true)))
2994 if (!await (Sender?.PresenceErrorBadRequest(Id, From, this.domainAddress,
"Invalid type.",
"en") ?? Task.FromResult(
true)))
2999 await this.PushPresence(To, Type, Id, UseBareJids ? From.
ToBareJID() : From, Language,
Stanza, UseBareJids, Sender);
3001 if (!(LastPresence is
null))
3003 await this.PushPresence(To, LastPresence.
Type, LastPresence.
Id, LastPresence.
From, LastPresence.
Language,
3004 LastPresence.
Stanza,
false, Sender);
3011 bool UseBareJids,
ISender Sender)
3030 await this.PushPresence(Type, Id, From, Language,
Stanza is
null ?
string.Empty :
Stanza.
Content, Connections, UseBareJids);
3039 await Rec.Item2.Presence(Type, Id, To, From, Language,
Stanza, Sender);
3067 return this.
Presence(Type, Id, To, From, Language, ToStanza(
"presence", Type, Id, To, From, Language, ContentXml), Sender);
3080 Type = stEx.ErrorType;
3081 Xml =
"<" + stEx.ErrorStanzaName +
" xmlns='" +
StanzaNamespace +
"'/>";
3089 if (ex is HTTP.BadRequestException)
3092 Xml =
"bad-request";
3094 else if (ex is HTTP.ConflictException)
3099 else if (ex is HTTP.ForbiddenException)
3104 else if (ex is HTTP.NotImplementedException)
3107 Xml =
"feature-not-implemented";
3109 else if (ex is HTTP.MovedPermanentlyException || ex is HTTP.GoneException)
3114 else if (ex is HTTP.InternalServerErrorException)
3117 Xml =
"internal-server-error";
3119 else if (ex is HTTP.NotFoundException)
3122 Xml =
"item-not-found";
3124 else if (ex is HTTP.NotAcceptableException || ex is HTTP.UnsupportedMediaTypeException)
3127 Xml =
"not-acceptable";
3129 else if (ex is HTTP.MethodNotAllowedException)
3132 Xml =
"not-allowed";
3134 else if (ex is HTTP.TooManyRequestsException || ex is HTTP.InsufficientStorageException)
3137 Xml =
"resource-constraint";
3139 else if (ex is HTTP.ServiceUnavailableException)
3142 Xml =
"service-unavailable";
3144 else if (ex is HTTP.NetworkAuthenticationRequiredException)
3147 Xml =
"not-authorized";
3163 #region Request/Response
3185 if (!(Connections is
null))
3191 if (!(Connection?.LastPresence is
null))
3194 if (Last is
null || LastPresence.
Timestamp > Last.Timestamp)
3195 Last = LastPresence;
3202 await
Callback.Raise(
this,
new PresenceEventArgs(
null, Last.Type, Last.Id, Last.To, Last.From, Last.Language, Last.Stanza, State));
3215 Endpoint = await this.GetS2sEndpoint(this.domain,
Domain,
true,
"Performing presence probe on " + BareJid);
3224 PendingRequest Request = this.PrepareRequest(
null, (Sender, e) =>
3227 },
null, State, 10000, 0,
false, 10000, this.domainAddress,
new XmppAddress(BareJid),
string.
Empty,
string.
Empty);
3242 private PendingRequest PrepareRequest(EventHandlerAsync<IqResultEventArgs> IqCallback, EventHandlerAsync<PresenceEventArgs> PresenceCallback,
3243 EventHandlerAsync<PendingRequestEventArgs> ResendCallback,
object State,
int RetryTimeout,
int NrRetries,
bool DropOff,
int MaxRetryTimeout,
3246 lock (this.synchObject)
3252 Id = this.
NewId(16);
3254 while (this.pendingRequestsById.ContainsKey(Id));
3256 PendingRequest PendingRequest;
3258 if (!(IqCallback is
null))
3260 PendingRequest =
new PendingRequest(Id, RetryTimeout, NrRetries, DropOff, MaxRetryTimeout)
3262 IqCallback = IqCallback,
3263 ResendCallback = ResendCallback,
3268 Language = Language,
3269 ContentXml = ContentXml
3274 PendingRequest =
new PendingRequest(Id, RetryTimeout, NrRetries, DropOff, MaxRetryTimeout)
3276 PresenceCallback = PresenceCallback,
3277 ResendCallback = ResendCallback,
3282 Language = Language,
3283 ContentXml = ContentXml
3287 DateTime TP = PendingRequest.Timeout;
3289 if (this.pendingRequestsByTimeout.ContainsKey(TP))
3291 Random Rnd =
new Random();
3293 while (this.pendingRequestsByTimeout.ContainsKey(TP))
3294 TP = TP.AddTicks(Rnd.Next(100) + 1);
3297 PendingRequest.Timeout = TP;
3299 this.pendingRequestsById[Id] = PendingRequest;
3300 this.pendingRequestsByTimeout[TP] = PendingRequest;
3302 return PendingRequest;
3317 public Task<bool>
SendIqRequest(
string Type,
string From,
string To,
string Language,
string ContentXml,
3318 EventHandlerAsync<IqResultEventArgs>
Callback,
object State)
3335 EventHandlerAsync<IqResultEventArgs>
Callback,
object State)
3341 PendingRequest Request = this.PrepareRequest(
Callback,
null, async (Sender, e) =>
3343 await Recipient.IQ(Type, e.Request.
Id, e.Request.
To, e.Request.
From,
3344 e.Request.
Language, e.Request.ContentXml,
this);
3346 }, State, this.defaultRetryTimeout, this.defaultNrRetries, this.defaultDropOff,
3347 this.defaultMaxRetryTimeout, From, To, Language, ContentXml);
3349 await Recipient.IQ(Type, Request.Id, To, From, Language, ContentXml,
this);
3371 public Task<IqResultEventArgs>
IqRequest(
string Type,
string From,
string To,
string Language,
string ContentXml)
3387 TaskCompletionSource<IqResultEventArgs> Result =
new TaskCompletionSource<IqResultEventArgs>();
3389 if (await this.
SendIqRequest(Type, From, To, Language, ContentXml, (Sender, e) =>
3391 Result.TrySetResult(e);
3392 return Task.CompletedTask;
3396 return await Result.Task;
3399 throw new InvalidOperationException(
"Unable to send request.");
3412 public Task<bool>
SendMessage(
string Type,
string Id,
string From,
string To,
string Language,
string ContentXml)
3433 await Recipient.Message(Type, Id, To, From, Language, ContentXml,
this);
3440 private async
void SecondTimerCallback(
object State)
3444 LinkedList<KeyValuePair<DateTime, IS2SEndpoint>> ToRemove =
null;
3445 List<PendingRequest> Retries =
null;
3446 DateTime Now = DateTime.Now;
3450 lock (this.synchObject)
3452 foreach (KeyValuePair<DateTime, PendingRequest> P
in this.pendingRequestsByTimeout)
3456 if (Retries is
null)
3457 Retries =
new List<PendingRequest>();
3459 Retries.Add(P.Value);
3465 if (!(this.temporaryConnections is
null))
3467 foreach (KeyValuePair<DateTime, IS2SEndpoint> P
in this.temporaryConnections)
3471 if (ToRemove is
null)
3472 ToRemove =
new LinkedList<KeyValuePair<DateTime, IS2SEndpoint>>();
3474 ToRemove.AddLast(P);
3480 if (!(ToRemove is
null))
3482 foreach (KeyValuePair<DateTime, IS2SEndpoint> P
in ToRemove)
3483 this.temporaryConnections.Remove(P.Key);
3485 if (this.temporaryConnections.Count == 0)
3486 this.temporaryConnections =
null;
3491 if (!(Retries is
null))
3493 foreach (PendingRequest Request
in Retries)
3495 lock (this.synchObject)
3497 this.pendingRequestsByTimeout.Remove(Request.Timeout);
3499 if (Retry = Request.CanRetry())
3501 TP = Request.Timeout;
3503 if (this.pendingRequestsByTimeout.ContainsKey(TP))
3505 Random Rnd =
new Random();
3507 while (this.pendingRequestsByTimeout.ContainsKey(TP))
3508 TP = TP.AddTicks(Rnd.Next(100) + 1);
3511 Request.Timeout = TP;
3513 this.pendingRequestsByTimeout[Request.Timeout] = Request;
3516 this.pendingRequestsById.Remove(Request.Id);
3522 await Request.ResendCallback.Raise(
this,
new PendingRequestEventArgs(Request));
3525 if (!(Request.IqCallback is
null))
3527 StringBuilder Xml =
new StringBuilder();
3529 Xml.Append(
"<iq xmlns='jabber:server' type='error' from='");
3530 Xml.Append(Request.To);
3531 Xml.Append(
"' id='");
3532 Xml.Append(Request.Id);
3533 Xml.Append(
"'><error type='wait'><recipient-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>");
3534 Xml.Append(
"<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Timeout.</text></error></iq>");
3536 XmlDocument Doc =
new XmlDocument()
3538 PreserveWhitespace =
true
3540 Doc.LoadXml(Xml.ToString());
3545 await Request.IqCallback.Raise(
this, e);
3547 else if (!(Request.PresenceCallback is
null))
3550 "<error type='wait'><recipient-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" +
3551 "<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Timeout.</text></error>");
3556 await Request.PresenceCallback.Raise(
this, e);
3560 catch (Exception ex)
3567 if (!(ToRemove is
null))
3569 foreach (KeyValuePair<DateTime, IS2SEndpoint> P
in ToRemove)
3570 await P.Value.DisposeAsync();
3573 catch (Exception ex)
3592 Stanza Stanza = ToStanza(
"iq",
"error", Id, To, From,
string.Empty, Xml);
3594 await this.ProcessResponse(
"error", Id, To, From,
string.Empty,
true,
false,
Stanza,
this);
3609 Stanza Stanza = ToStanza(
"iq",
"error", Id, To, From,
string.Empty, ErrorXml);
3611 await this.ProcessResponse(
"error", Id, To, From,
string.Empty,
true,
false,
Stanza,
this);
3626 Stanza Stanza = ToStanza(
"iq",
"result", Id, To, From,
string.Empty, ResultXml);
3628 await this.ProcessResponse(
"result", Id, To, From,
string.Empty,
true,
false,
Stanza,
this);
3644 Stanza Stanza = ToStanza(
"presence",
"error", Id, To, From,
string.Empty, Xml);
3646 await this.ProcessResponse(
"error", Id, To, From,
string.Empty,
false,
true,
Stanza,
this);
3661 Stanza Stanza = ToStanza(
"presence",
"error", Id, To, From,
string.Empty, ErrorXml);
3663 await this.ProcessResponse(
"error", Id, To, From,
string.Empty,
false,
true,
Stanza,
this);
3680 Stanza Stanza = ToStanza(
"presence", Type, Id, To, From,
string.Empty, ContentXml);
3682 await this.ProcessResponse(Type, Id, To, From,
string.Empty,
true,
false,
Stanza,
this);
3699 return Task.FromResult(
true);
3712 return Task.FromResult(
true);
3721 private async Task RosterQuery(
object Sender,
IqEventArgs e)
3730 IEnumerable<IRosterItem> Roster = await this.persistenceLayer.GetRoster(UserName);
3739 List<IRosterItem>
A =
new List<IRosterItem>();
3741 A.Sort((i1, i2) => i1.BareJid.CompareTo(i2.BareJid));
3743 StringBuilder Xml =
new StringBuilder();
3746 this.Serialize(Xml,
Item);
3756 Xml.Append(
"<query xmlns='");
3758 Xml.Append(
"' ver='");
3762 Xml.Append(
"</query>");
3770 Xml.Append(
"<item jid='");
3774 Xml.Append(
"' ask='subscribe");
3776 if (!
string.IsNullOrEmpty(
Item.
Name))
3778 Xml.Append(
"' name='");
3784 Xml.Append(
"' subscription='");
3788 string[] Groups =
Item.Groups;
3789 if (Groups is
null || Groups.Length == 0)
3795 foreach (
string Group
in Groups)
3797 Xml.Append(
"<group>");
3799 Xml.Append(
"</group>");
3802 Xml.Append(
"</item>");
3806 private async Task RosterSet(
object Sender,
IqEventArgs e)
3815 List<string> Groups =
null;
3824 foreach (XmlNode N
in e.
Query.ChildNodes)
3826 E = N as XmlElement;
3830 if (E.LocalName !=
"item")
3852 foreach (XmlNode N2
in N.ChildNodes)
3854 E = N2 as XmlElement;
3858 if (E.LocalName !=
"group")
3862 Groups =
new List<string>();
3870 else if (Groups.Contains(s))
3886 IRosterItem Item = await this.persistenceLayer.SetRosterItem(UserName, Jid, Name,
null,
null, Groups?.ToArray());
3887 if (!(
Item is
null))
3891 if (await this.persistenceLayer.RemoveRosterItem(UserName, Jid))
3910 StringBuilder Xml =
new StringBuilder();
3912 Xml.Append(
"<query xmlns='");
3914 Xml.Append(
"'><item jid='");
3916 Xml.Append(
"' subscription='remove'></item></query>");
3935 StringBuilder Xml =
new StringBuilder();
3937 Xml.Append(
"<query xmlns='");
3941 this.Serialize(Xml,
Item);
3943 Xml.Append(
"</query>");
3950 if (!(Connections is
null))
3960 catch (Exception ex)
3967 catch (Exception ex2)
3977 private async Task PushPresence(
string Type,
string Id,
XmppAddress From,
string Language,
string Xml,
IClientConnection[] Connections,
3980 if (!(Connections is
null))
3988 await Connection.
Presence(Type,
string.IsNullOrEmpty(Id) ? this.
NewId(16) : Id,
3989 UseBareJids ? Connection.
BareAddress : Connection.
Address, From, Language, Xml,
this);
3991 catch (Exception ex)
3998 catch (Exception ex2)
4010 #region Ping XEP-0199
4012 private Task PingGet(
object Sender,
IqEventArgs e)
4016 return Task.CompletedTask;
4021 #region Discovery XEP-0030
4023 private Task DiscoveryQueryGet(
object Sender,
IqEventArgs e)
4025 XmlElement E = e.
Query;
4027 if (!
string.IsNullOrEmpty(Node))
4030 return Task.CompletedTask;
4033 StringBuilder Xml =
new StringBuilder();
4035 Xml.Append(
"<query xmlns='");
4037 Xml.Append(
"'><identity category='server' type='im'/>");
4039 lock (this.synchObject)
4041 foreach (
string Feature
in this.features.Keys)
4043 Xml.Append(
"<feature var='");
4049 Xml.Append(
"</query>");
4053 return Task.CompletedTask;
4056 private Task DiscoveryQueryItemsGet(
object Sender,
IqEventArgs e)
4058 XmlElement E = e.
Query;
4060 if (!
string.IsNullOrEmpty(Node))
4063 return Task.CompletedTask;
4066 StringBuilder Xml =
new StringBuilder();
4068 Xml.Append(
"<query xmlns='");
4074 Xml.Append(
"<item jid='");
4078 Xml.Append(
"' name='");
4083 Xml.Append(
"</query>");
4087 return Task.CompletedTask;
4092 #region Software Version (XEP-0092)
4094 private Task SoftwareVersionGet(
object Sender,
IqEventArgs e)
4096 StringBuilder Xml =
new StringBuilder();
4098 Xml.Append(
"<query xmlns='");
4100 Xml.Append(
"'><name>");
4101 Xml.Append(
XML.
Encode(
this.serverName));
4102 Xml.Append(
"</name><version>");
4103 Xml.Append(
XML.
Encode(
this.serverVersion));
4104 Xml.Append(
"</version><os>");
4106 Xml.Append(
"</os></query>");
4110 return Task.CompletedTask;
4115 #region Entity Time (XEP-0202)
4117 private Task TimeGet(
object Sender,
IqEventArgs e)
4119 StringBuilder Xml =
new StringBuilder();
4120 DateTimeOffset Time = DateTimeOffset.Now;
4121 TimeSpan TimeZone = Time.Offset;
4122 DateTime Utc = Time.UtcDateTime;
4124 Xml.Append(
"<time xmlns='");
4126 Xml.Append(
"'><tzo>");
4128 if (TimeZone == TimeSpan.Zero)
4132 if (TimeZone < TimeSpan.Zero)
4135 TimeZone = -TimeZone;
4140 Xml.Append(TimeZone.Hours.ToString(
"D2"));
4142 Xml.Append(TimeZone.Minutes.ToString(
"D2"));
4145 Xml.Append(
"</tzo><utc>");
4147 Xml.Append(
"</utc></time>");
4151 return Task.CompletedTask;
4156 #region vCard (XEP-0054)
4158 private async Task VCardGet(
object Sender,
IqEventArgs e)
4164 string s = await this.persistenceLayer.GetVCard(e.
From.
Account);
4166 if (
string.IsNullOrEmpty(s))
4173 private async Task VCardSet(
object Sender,
IqEventArgs e)
4180 string VCard = e.
Query.InnerXml;
4182 if (!await this.persistenceLayer.SetVCard(UserName, VCard))
4191 #region Register (XEP-0077) & Form signatures (XEP-0348)
4193 private const string RegistrationInstructions =
"Register your new account, by filling in the details below.";
4198 return !Next.HasValue;
4207 StringBuilder sb =
new StringBuilder();
4208 DateTime TP = Next.Value;
4209 DateTime Today = DateTime.Today;
4211 if (Next.Value == DateTime.MaxValue)
4213 sb.Append(
"This endpoint (");
4215 sb.Append(
") has been blocked from the system.");
4222 sb.Append(
"Too many failed login attempts in a row registered. Try again after ");
4223 sb.Append(TP.ToLongTimeString());
4225 if (TP.Date != Today)
4227 if (TP.Date == Today.AddDays(1))
4228 sb.Append(
" tomorrow");
4232 sb.Append(TP.ToShortDateString());
4236 sb.Append(
". Remote Endpoint: ");
4247 private async Task RegisterGet(
object Sender,
IqEventArgs e)
4255 if (!await this.CanRegister(Connection, e))
4258 StringBuilder Xml =
new StringBuilder();
4262 Xml.Append(
"<query xmlns='");
4264 Xml.Append(
"'><instructions>");
4265 Xml.Append(RegistrationInstructions);
4266 Xml.Append(
"</instructions>");
4267 Xml.Append(
"<x xmlns='jabber:x:data' type='form'>");
4268 Xml.Append(
"<title>Contest Registration</title>");
4269 Xml.Append(
"<instructions>");
4270 Xml.Append(RegistrationInstructions);
4271 Xml.Append(
"</instructions>");
4272 Xml.Append(
"<field type='hidden' var='FORM_TYPE'>");
4273 Xml.Append(
"<value>urn:xmpp:xdata:signature:oauth1</value>");
4274 Xml.Append(
"</field>");
4275 Xml.Append(
"<field type='text-single' label='User Name:' var='username'>");
4276 Xml.Append(
"<required/>");
4277 Xml.Append(
"</field>");
4278 Xml.Append(
"<field type='text-private' label='Password:' var='password'>");
4279 Xml.Append(
"<required/>");
4280 Xml.Append(
"</field>");
4281 Xml.Append(
"<field type='text-single' label='Email Address' var='email'/>");
4282 Xml.Append(
"<field type='text-single' label='Phone Number' var='phone'/>");
4283 Xml.Append(
"<field type='hidden' var='oauth_version'>");
4284 Xml.Append(
"<value>1.0</value>");
4285 Xml.Append(
"</field>");
4286 Xml.Append(
"<field type='hidden' var='oauth_signature_method'>");
4287 Xml.Append(
"<value>HMAC-SHA1</value>");
4288 Xml.Append(
"</field>");
4289 Xml.Append(
"<field type='hidden' var='oauth_token'>");
4290 Xml.Append(
"<value>");
4292 Xml.Append(
"</value>");
4293 Xml.Append(
"</field>");
4294 Xml.Append(
"<field type='hidden' var='oauth_token_secret'>");
4295 Xml.Append(
"<value>");
4297 Xml.Append(
"</value>");
4298 Xml.Append(
"</field>");
4299 Xml.Append(
"<field type='hidden' var='oauth_nonce'>");
4300 Xml.Append(
"<value/>");
4301 Xml.Append(
"</field>");
4302 Xml.Append(
"<field type='hidden' var='oauth_timestamp'>");
4303 Xml.Append(
"<value/>");
4304 Xml.Append(
"</field>");
4305 Xml.Append(
"<field type='hidden' var='oauth_consumer_key'>");
4306 Xml.Append(
"<value/>");
4307 Xml.Append(
"</field>");
4308 Xml.Append(
"<field type='hidden' var='oauth_signature'>");
4309 Xml.Append(
"<value/>");
4310 Xml.Append(
"</field>");
4312 Xml.Append(
"</query>");
4317 private async Task RegisterSet(
object Sender,
IqEventArgs e)
4325 if (!await this.CanRegister(Connection, e))
4329 string Password =
null;
4333 foreach (XmlNode N
in e.
Query.ChildNodes)
4335 if (!(N is XmlElement E))
4341 switch (E.LocalName)
4344 UserName = E.InnerText;
4348 Password = E.InnerText;
4367 string OAuthVersion =
null;
4368 string OAuthSignatureMethod =
null;
4369 string OAuthToken =
null;
4370 string OAuthTokenSecret =
null;
4371 string OAuthNonce =
null;
4372 string OAuthTimestamp =
null;
4373 string OAuthConsumerKey =
null;
4374 string OAuthSignature =
null;
4376 foreach (XmlNode N2
in E.ChildNodes)
4378 if (N2.LocalName ==
"field")
4381 string Value =
null;
4383 foreach (XmlNode N3
in N2.ChildNodes)
4385 if (N3.LocalName ==
"value")
4387 Value = N3.InnerText;
4417 case "oauth_version":
4418 OAuthVersion = Value;
4421 case "oauth_signature_method":
4422 OAuthSignatureMethod = Value;
4429 case "oauth_token_secret":
4430 OAuthTokenSecret = Value;
4437 case "oauth_timestamp":
4438 OAuthTimestamp = Value;
4441 case "oauth_consumer_key":
4442 OAuthConsumerKey = Value;
4445 case "oauth_signature":
4446 OAuthSignature = Value;
4455 bool Signed =
false;
4456 bool Logged =
false;
4458 if (FormType ==
"urn:xmpp:xdata:signature:oauth1" && OAuthVersion ==
"1.0" && !
string.IsNullOrEmpty(UserName) &&
4459 !
string.IsNullOrEmpty(Password) && !(EMail is
null) && !(PhoneNr is
null) && !
string.IsNullOrEmpty(OAuthSignatureMethod) &&
4460 !
string.IsNullOrEmpty(OAuthToken) && !
string.IsNullOrEmpty(OAuthTokenSecret) && !
string.IsNullOrEmpty(OAuthNonce) &&
4461 !
string.IsNullOrEmpty(OAuthTimestamp) && !
string.IsNullOrEmpty(OAuthConsumerKey) && !
string.IsNullOrEmpty(OAuthSignature))
4463 string KeySecret = await this.persistenceLayer.GetApiKeySecret(OAuthConsumerKey);
4464 if (!
string.IsNullOrEmpty(KeySecret))
4466 StringBuilder PStr =
new StringBuilder();
4468 PStr.Append(
"email=");
4469 PStr.Append(OAuthEncode(EMail));
4470 PStr.Append(
"&FORM_TYPE=");
4471 PStr.Append(OAuthEncode(FormType));
4472 PStr.Append(
"&oauth_consumer_key=");
4473 PStr.Append(OAuthEncode(OAuthConsumerKey));
4474 PStr.Append(
"&oauth_nonce=");
4475 PStr.Append(OAuthEncode(OAuthNonce));
4476 PStr.Append(
"&oauth_signature_method=");
4477 PStr.Append(OAuthEncode(OAuthSignatureMethod));
4478 PStr.Append(
"&oauth_timestamp=");
4479 PStr.Append(OAuthEncode(OAuthTimestamp));
4480 PStr.Append(
"&oauth_token=");
4481 PStr.Append(OAuthEncode(OAuthToken));
4482 PStr.Append(
"&oauth_version=");
4483 PStr.Append(OAuthEncode(OAuthVersion));
4484 PStr.Append(
"&password=");
4485 PStr.Append(OAuthEncode(Password));
4486 PStr.Append(
"&phone=");
4487 PStr.Append(OAuthEncode(PhoneNr));
4488 PStr.Append(
"&username=");
4489 PStr.Append(OAuthEncode(UserName));
4491 StringBuilder BStr =
new StringBuilder();
4493 BStr.Append(
"submit&&");
4494 BStr.Append(OAuthEncode(PStr.ToString()));
4496 byte[] Key = Encoding.ASCII.GetBytes(OAuthEncode(KeySecret) +
"&" + OAuthEncode(OAuthTokenSecret));
4499 switch (OAuthSignatureMethod)
4507 LoginAuditor.
Fail(
"Registration form signature failed. Unhandled signature method requested.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4508 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4509 new KeyValuePair<string, object>(
"Method", OAuthSignatureMethod),
4510 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4511 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4515 if (!(Hash is
null))
4517 string Signature = OAuthEncode(Convert.ToBase64String(Hash));
4518 Signed = Signature == OAuthSignature;
4523 LoginAuditor.
Fail(
"Registration form signature failed.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4524 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4525 new KeyValuePair<string, object>(
"Method", OAuthSignatureMethod),
4526 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4527 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4534 LoginAuditor.
Fail(
"Registration form signature failed. Invalid API key used.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4535 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4536 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4537 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4543 LoginAuditor.
Fail(
"Registration form signature failed. Signature parameters not provided.", UserName, Connection.RemoteEndpoint, Connection.Protocol);
4548 if (
string.IsNullOrEmpty(UserName))
4551 if (UserName.
Length > 1023)
4556 if (
char.IsWhiteSpace(ch))
4558 await e.
IqErrorNotAllowed(e.
To,
"White-space characters not allowed in user names.",
"en");
4574 KeyValuePair<IAccount, string[]> P = await this.persistenceLayer.CreateAccount(OAuthConsumerKey, UserName, Password, EMail, PhoneNr, Connection.RemoteEndpoint);
4576 if (Account is
null)
4578 string[] Alternatives = P.Value;
4579 StringBuilder Xml =
new StringBuilder();
4581 Xml.Append(
"<conflict xmlns='");
4585 if (!(Alternatives is
null) && Alternatives.Length > 0)
4587 Xml.Append(
"<alternatives xmlns='");
4591 foreach (
string Alternative
in Alternatives)
4593 Xml.Append(
"<alternative>");
4595 Xml.Append(
"</alternative>");
4598 Xml.Append(
"</alternatives>");
4602 "Account name already exists, or API key limit reached.",
"en");
4605 LoginAuditor.
Fail(
"Registration failed. Signature OK, but account already exists, or API key limit reached.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4606 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4607 new KeyValuePair<string, object>(
"Method", OAuthSignatureMethod),
4608 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4609 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4616 LoginAuditor.
Success(
"Registration successful and account created.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4617 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4618 new KeyValuePair<string, object>(
"Method", OAuthSignatureMethod),
4619 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4620 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4627 LoginAuditor.
Fail(
"Registration form signature failed.", UserName, Connection.RemoteEndpoint, Connection.Protocol,
4628 new KeyValuePair<string, object>(
"ApiKey", OAuthConsumerKey),
4629 new KeyValuePair<string, object>(
"Method", OAuthSignatureMethod),
4630 new KeyValuePair<string, object>(
"EMail", EMail?.Value),
4631 new KeyValuePair<string, object>(
"PhoneNr", PhoneNr?.Value));
4646 await e.
IqErrorForbidden(e.
To,
"Only allowed to remove your own account, while account is active.",
"en");
4649 await e.
IqError(
"auth",
"<registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>", e.
To,
4650 "Only accounts registered on the broker can remove their accounts.",
"en");
4652 else if (await this.persistenceLayer.DeleteAccount(e.
From.
Account, Connection.RemoteEndpoint))
4655 Connection.AccountDeleted();
4659 await e.
IqError(
"auth",
"<registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>", e.
To,
4660 "Only accounts registered on the broker can remove their accounts.",
"en");
4666 if (!
string.IsNullOrEmpty(UserName) && !
string.IsNullOrEmpty(Password))
4669 !await
this.persistenceLayer.ChangePassword(UserName, Password))
4687 foreach (
char ch
in UserName)
4753 private static string OAuthEncode(
string s)
4755 StringBuilder Result =
new StringBuilder();
4757 foreach (
char ch
in s)
4759 if (OAuthReserved.IndexOf(ch) < 0)
4762 Result.Append(((
int)ch).
ToString(
"X2"));
4768 return Result.ToString();
4771 private const string OAuthReserved =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
4775 #region Blocking Command (XEP-0191) and Spam Reporting (XEP-0377).
4777 private async Task BlockListGet(
object Sender,
IqEventArgs e)
4781 await e.
IqErrorForbidden(e.
To,
"Access to block list can only be granted from the corresponding client.",
"en");
4785 IEnumerable<CaseInsensitiveString> BlockList = await this.persistenceLayer.GetBlockList(Connection.UserName);
4786 if (BlockList is
null)
4792 Connection.WantsBlockList =
true;
4794 StringBuilder Xml =
new StringBuilder();
4796 Xml.Append(
"<blocklist xmlns='");
4802 Xml.Append(
"<item jid='");
4807 Xml.Append(
"</blocklist>");
4812 private async Task BlockSet(
object Sender,
IqEventArgs e)
4816 await e.
IqErrorForbidden(e.
To,
"Access to block list can only be granted from the corresponding client.",
"en");
4821 List<CaseInsensitiveString> BareJids =
null;
4822 string Text =
string.Empty;
4823 string TextLanguage =
string.Empty;
4826 foreach (XmlNode N
in e.
Query.ChildNodes)
4828 switch (N.LocalName)
4838 if (BareJids is
null)
4839 BareJids =
new List<CaseInsensitiveString>();
4841 BareJids.Add(BareJid);
4845 foreach (XmlNode N2
in N.ChildNodes)
4847 switch (N2.LocalName)
4850 XmlElement E = (XmlElement)N2;
4868 if (BareJids is
null)
4874 StringBuilder Xml =
null;
4878 if (await this.persistenceLayer.AddBlock(Connection.UserName, BareJid2, Reason, Text, TextLanguage))
4882 if (!(Connections is
null))
4889 Xml =
new StringBuilder();
4893 Xml.Append(
"<block xmlns='");
4895 Xml.Append(
"'><item jid='");
4896 Xml.Append(BareJid2);
4897 Xml.Append(
"'/></block>");
4903 catch (Exception ex)
4905 await Connection.Exception(ex);
4906 await Connection.DisposeAsync();
4917 private async Task UnblockSet(
object Sender,
IqEventArgs e)
4921 await e.
IqErrorForbidden(e.
To,
"Access to block list can only be granted from the corresponding client.",
"en");
4925 List<CaseInsensitiveString> BareJids =
null;
4928 foreach (XmlNode N
in e.
Query.ChildNodes)
4930 if (N.LocalName ==
"item")
4939 if (BareJids is
null)
4940 BareJids =
new List<CaseInsensitiveString>();
4942 BareJids.Add(BareJid);
4946 if (BareJids is
null)
4948 if (await this.persistenceLayer.ClearBlocks(Connection.UserName))
4952 if (!(Connections is
null))
4960 await Connection2.
IQ(
"set",
string.Empty, Connection2.
Address, e.
To,
string.
Empty,
4963 catch (Exception ex)
4967 await Connection.Exception(ex);
4968 await Connection.DisposeAsync();
4970 catch (Exception ex2)
4982 StringBuilder Xml =
null;
4986 if (await this.persistenceLayer.Unblock(Connection.UserName, BareJid2))
4990 if (!(Connections is
null))
4997 Xml =
new StringBuilder();
5001 Xml.Append(
"<unblock xmlns='");
5003 Xml.Append(
"'><item jid='");
5004 Xml.Append(BareJid2);
5005 Xml.Append(
"'/></unblock>");
5011 catch (Exception ex)
5013 await Connection.Exception(ex);
5014 await Connection.DisposeAsync();
5035 FileName = this.domainSnifferPath.Replace(
"%DOMAIN%", Key);
5037 FileName = this.clientSnifferPath.Replace(
"%ENDPOINT%", Key);
5046 foreach (
ISniffer Sniffer
in Endpoint.Sniffers)
5049 return XmlFileSniffer2;
5056 if (!(Connections is
null))
5065 return XmlFileSniffer2;
5075 internal void CacheSniffers(IEnumerable<ISniffer> Sniffers)
5077 foreach (
ISniffer Sniffer
in Sniffers)
5081 else if (Sniffer is IDisposable Disposable)
5082 Disposable.Dispose();
5088 if (this.sniffers is
null)
5091 this.sniffers.Removed += this.Sniffers_Removed;
5099 if (this.disposed || (DateTime.Now - e.
Value.LastEvent).TotalMinutes > 30)
5102 return Task.CompletedTask;
5113 internal void DataReceived(
int NrRead)
5115 lock (this.statSync)
5117 this.nrBytesRx += NrRead;
5125 internal void DataTransmitted(
int NrWritten)
5127 lock (this.statSync)
5129 this.nrBytesTx += NrWritten;
5143 string Namespace =
null;
5144 string LocalName =
null;
5145 string LocalNameBak =
null;
5146 string ns = StanzaElement.NamespaceURI;
5148 foreach (XmlNode N
in StanzaElement.ChildNodes)
5150 if (N is XmlElement E)
5152 if (E.NamespaceURI != ns)
5154 Namespace = E.NamespaceURI;
5155 LocalName = E.LocalName;
5158 else if (LocalNameBak is
null)
5159 LocalNameBak = E.LocalName;
5163 if (Namespace is
null)
5165 Namespace = StanzaElement.NamespaceURI;
5166 LocalName = LocalNameBak ??
string.Empty;
5169 lock (this.statSync)
5173 this.IncLocked(
Stanza +
"#" + Type, this.stanzasPerStanzaType);
5174 this.IncLocked(From.
Domain,
this.stanzasPerFromDomain);
5175 this.IncLocked(From.
BareJid,
this.stanzasPerFromBareJid);
5176 this.IncLocked(To.
Domain,
this.stanzasPerToDomain);
5177 this.IncLocked(To.
BareJid,
this.stanzasPerToBareJid);
5178 this.IncLocked(Namespace, this.stanzasPerNamespace);
5179 this.IncLocked(Namespace +
"#" + LocalName, this.stanzasPerFqn);
5183 private void IncLocked(
string Key, Dictionary<string, Statistic> Stat)
5185 if (!Stat.TryGetValue(Key, out
Statistic Rec))
5201 DateTime TP = DateTime.Now;
5203 lock (this.statSync)
5205 Result =
new Statistics.CommunicationStatistics()
5207 StanzasPerStanzaType = this.stanzasPerStanzaType,
5208 StanzasPerFromDomain = this.stanzasPerFromDomain,
5209 StanzasPerToDomain = this.stanzasPerToDomain,
5210 StanzasPerFromBareJid = this.stanzasPerFromBareJid,
5211 StanzasPerToBareJid = this.stanzasPerToBareJid,
5212 StanzasPerNamespace = this.stanzasPerNamespace,
5213 StanzasPerFqn = this.stanzasPerFqn,
5214 LastStat = this.lastStat,
5216 NrBytesRx = this.nrBytesRx,
5217 NrBytesTx = this.nrBytesTx,
5218 NrStanzas = this.nrStanzas
5221 this.stanzasPerStanzaType =
new Dictionary<string, Statistic>();
5222 this.stanzasPerFromDomain =
new Dictionary<string, Statistic>();
5223 this.stanzasPerToDomain =
new Dictionary<string, Statistic>();
5224 this.stanzasPerFromBareJid =
new Dictionary<string, Statistic>();
5225 this.stanzasPerToBareJid =
new Dictionary<string, Statistic>();
5226 this.stanzasPerNamespace =
new Dictionary<string, Statistic>();
5227 this.stanzasPerFqn =
new Dictionary<string, Statistic>();
5239 #region XEP-0049: Private XML Storage
5241 internal async Task PrivateXmlStorageGet(
object Sender,
IqEventArgs e)
5245 await e.
IqErrorForbidden(e.
To,
"Private storage only accessible from clients directly connected to the server.",
"en");
5249 IAccount FromAccount = await this.persistenceLayer.GetAccount(Connection.UserName);
5250 if (FromAccount is
null)
5256 StringBuilder Xml =
new StringBuilder();
5260 Xml.Append(
"<query xmlns='");
5264 foreach (XmlNode N
in e.
Query.ChildNodes)
5266 if (N is XmlElement E)
5280 Xml.Append(Element.
Xml);
5299 Xml.Append(
"</query>");
5304 internal async Task PrivateXmlStorageSet(
object Sender,
IqEventArgs e)
5308 await e.
IqErrorForbidden(e.
To,
"Private storage only accessible from clients directly connected to the server.",
"en");
5312 IAccount FromAccount = await this.persistenceLayer.GetAccount(Connection.UserName);
5313 if (FromAccount is
null)
5322 foreach (XmlNode N
in e.
Query.ChildNodes)
5324 if (N is XmlElement E)
5326 bool DeleteElement = IsEmptyPrivateXml(E);
5344 Element.Xml = E.OuterXml;
5345 Element.Updated = DateTime.UtcNow;
5354 if (Found || DeleteElement)
5357 DateTime TP = DateTime.UtcNow;
5362 Namespace = E.NamespaceURI,
5363 LocalName = E.LocalName,
5377 private static bool IsEmptyPrivateXml(XmlElement E)
5379 if (E.HasChildNodes)
5382 foreach (XmlAttribute Attr
in E.Attributes)
5384 if (Attr.Name !=
"xmlns")
5393 #region SMTP integration
5408 List<KeyValuePair<string, object>> Tags =
new List<KeyValuePair<string, object>>();
5410 foreach (KeyValuePair<string, string> P
in Message.AllHeaders)
5411 Tags.Add(
new KeyValuePair<string, object>(P.Key, P.Value));
5427 Dictionary<CaseInsensitiveString, bool> Processed =
new Dictionary<CaseInsensitiveString, bool>();
5433 catch (Exception ex)
5441 if (!(Recipients is
null))
5443 foreach (MailAddress Recipient
in Recipients)
5445 if (!Processed.ContainsKey(Recipient.Address))
5447 Processed[Recipient.Address] =
true;
5454 private readonly Dictionary<string, DateTime> lastBounce =
new Dictionary<string, DateTime>();
5456 private bool CanReturnBounceMessage(MailAddress Recipient, MailAddress Sender)
5458 string Key = Recipient.Address +
" | " + Sender.Address;
5461 lock (this.lastBounce)
5463 if (this.lastBounce.ContainsKey(Key))
5467 TP = scheduler.
Add(DateTime.Now.AddHours(4), (P) =>
5469 lock (this.lastBounce)
5471 this.lastBounce.Remove((string)P);
5475 lock (this.lastBounce)
5477 this.lastBounce[Key] = TP;
5483 private async Task ProcessMessage(
SmtpMessage Message, MailAddress Recipient)
5488 if (this.IsServerDomain(Addr.
Domain,
true))
5491 StringBuilder Markdown;
5498 if (!this.CanReturnBounceMessage(Recipient, Message.
FromMail))
5504 Markdown =
new StringBuilder();
5506 Markdown.AppendLine(
"Welcome");
5507 Markdown.AppendLine(
"===========");
5508 Markdown.AppendLine();
5510 Markdown.Append(
"The mail server at **");
5512 Markdown.AppendLine(
"** only forwards mail messages from approved senders.");
5513 Markdown.Append(
"Since **");
5515 Markdown.Append(
"** has not been approved by **");
5517 Markdown.AppendLine(
"**, your mail has not been forwarded.");
5518 Markdown.AppendLine();
5520 if (this.httpServer.OpenHttpsPorts.Length > 0 ||
this.httpServer.OpenHttpPorts.Length > 0)
5522 Markdown.Append(
"If you want, you can send a request to **");
5524 Markdown.Append(
"** to become approved, by following this link: [Request approval](");
5525 Markdown.Append(
"http");
5527 if (this.httpServer.OpenHttpsPorts.Length > 0)
5529 Markdown.Append(
"s://");
5530 Markdown.Append(this.domain);
5534 Markdown.Append(
':');
5535 Markdown.Append(this.httpServer.OpenHttpsPorts[0]);
5540 Markdown.Append(
"://");
5541 Markdown.Append(this.domain);
5545 Markdown.Append(
':');
5546 Markdown.Append(this.httpServer.OpenHttpPorts[0]);
5550 string Expires = DateTime.Now.AddDays(1).Ticks.ToString();
5552 Markdown.Append(
"/RequestWhiteList?Sender=");
5554 Markdown.Append(
"&Receiver=");
5556 Markdown.Append(
"&Expires=P");
5557 Markdown.Append(Expires);
5558 Markdown.Append(
"&MAC=");
5560 StringBuilder sb =
new StringBuilder();
5561 sb.Append(Message.
FromMail.Address);
5563 sb.Append(Recipient.Address);
5570 if (
string.IsNullOrEmpty(Key))
5572 Key = Convert.ToBase64String(GetRandomNumbers(32));
5576 RequestWhiteList.whiteListKey = Key;
5580 Encoding.UTF8.GetBytes(sb.ToString()));
5582 Markdown.Append(MAC);
5583 Markdown.AppendLine(
")");
5584 Markdown.AppendLine();
5586 Log.
Notice(
"Mail discarded. Bounce message returned.", Recipient.Address, Message.
FromMail.Address,
5587 new KeyValuePair<string, object>(
"Sender", Message.
FromMail.Address),
5588 new KeyValuePair<string, object>(
"Receiver", Recipient.Address),
5589 new KeyValuePair<string, object>(
"Expires", Expires),
5590 new KeyValuePair<string, object>(
"MAC", MAC));
5593 await this.SendMailMessage(Recipient.Address, Message.
FromMail.Address,
"Approval required", Markdown.ToString());
5599 ISender Sender = await this.GetS2sEndpoint(To.
Domain, From.
Domain,
true,
"Forwarding e-mail.");
5600 List<EmbeddedContent> Attachments =
null;
5601 List<EmbeddedContent> Inline =
null;
5603 string PlainText =
null;
5607 if (!(Sender is
null))
5611 Attachments =
new List<EmbeddedContent>();
5617 Inline =
new List<EmbeddedContent>();
5623 LinkedList<MultipartContent> ToProcess =
new LinkedList<MultipartContent>();
5628 while (!(ToProcess.First is
null))
5631 ToProcess.RemoveFirst();
5644 ToProcess.AddLast(MultipartContent2);
5645 else if (Decoded is
null)
5649 if (Attachments is
null)
5650 Attachments =
new List<EmbeddedContent>();
5663 if (Attachments is
null)
5664 Attachments =
new List<EmbeddedContent>();
5671 Inline =
new List<EmbeddedContent>();
5678 ToProcess.AddLast(MultipartContent2);
5679 else if (Decoded is
null)
5683 if (Attachments is
null)
5684 Attachments =
new List<EmbeddedContent>();
5695 if (!(Decoded is
null))
5697 if (PlainText is
null && Decoded is
string s)
5699 else if (Html is
null && Decoded is
HtmlDocument Html2)
5709 if (
string.IsNullOrEmpty(PlainText))
5716 StringBuilder Content =
new StringBuilder();
5717 bool HasBody =
false;
5719 if (!
string.IsNullOrEmpty(Message.
Subject))
5721 Content.Append(
"<subject>");
5723 Content.Append(
"</subject>");
5726 if (!
string.IsNullOrEmpty(Message.
MessageID))
5728 Content.Append(
"<thread>");
5730 Content.Append(
"</thread>");
5733 if (!
string.IsNullOrEmpty(PlainText))
5735 Content.Append(
"<body>");
5737 Content.Append(
"</body>");
5742 if (!(Html?.Body is
null))
5744 Content.Append(
"<html xmlns='http://jabber.org/protocol/xhtml-im'>");
5745 Content.Append(
"<body xmlns='http://www.w3.org/1999/xhtml'>");
5747 if (Html.
Body.HasChildren)
5753 Content.Append(
"</body></html>");
5760 Content.Append(
"<content xmlns='");
5761 Content.Append(ContentNamespace);
5762 Content.Append(
"' type='text/markdown'>");
5764 Content.Append(
"</content>");
5771 Markdown =
new StringBuilder();
5773 Markdown.AppendLine(
"Unable to process incoming message");
5774 Markdown.AppendLine(
"=======================================");
5775 Markdown.AppendLine();
5777 Markdown.Append(
"The mail server at **");
5779 Markdown.AppendLine(
"** was unable to forward the mail message to **");
5781 Markdown.Append(
"**), since the content type `");
5783 Markdown.AppendLine(
"` is not handled.");
5785 await this.SendMailMessage(Recipient.Address, Message.
FromMail.Address,
"Unable to process incoming message", Markdown.ToString());
5787 Log.
Notice(
"Mail discarded due to unhandled Content-Type.", Recipient.Address, Message.
FromMail.Address,
5788 new KeyValuePair<string, object>(
"Content-Type", Message.
ContentType));
5793 Content.Append(
"<mailInfo xmlns='urn:xmpp:smtp' contentType='");
5796 if (!
string.IsNullOrEmpty(Message.
MessageID))
5798 Content.Append(
"' id='");
5802 Content.Append(
"' priority='");
5803 Content.Append(((
int)Message.
Priority).ToString());
5805 if (Message.
Date.HasValue)
5807 Content.Append(
"' date='");
5811 Content.Append(
"' fromMail='");
5814 Content.Append(
"' fromHeader='");
5817 Content.Append(
"' sender='");
5820 DateTime TP = DateTime.Now;
5827 ContentId = Guid.NewGuid().ToString()
5832 Content.Append(
"' size='");
5835 Content.Append(
"' cid='");
5838 Content.Append(
"'><headers xmlns='http://jabber.org/protocol/shim'>");
5840 foreach (KeyValuePair<string, string> P
in Message.
AllHeaders)
5842 Content.Append(
"<header name='");
5844 Content.Append(
"'>");
5846 Content.Append(
"</header>");
5849 Content.Append(
"</headers>");
5851 await this.Serialize(Content, Attachments?.ToArray(),
"attachment", Addr);
5852 await this.Serialize(Content, Inline?.ToArray(),
"inline", Addr);
5854 Content.Append(
"</mailInfo>");
5856 await this.Message(
"chat",
string.Empty, To, From,
string.Empty, Content.ToString(), Sender);
5862 IS2SEndpoint S2sEndpoint = await this.GetS2sEndpoint(this.domain, Addr.
Domain,
true,
"Relaying incoming mail message.");
5867 catch (Exception ex)
5877 if (E.Name.IndexOf(
':') >= 0)
5880 switch (E.Name.ToUpper())
5917 Output.Append(E.Name);
5919 if (E.HasAttributes)
5923 if (Attr.
Name.IndexOf(
':') >= 0)
5927 Output.Append(Attr.
Name);
5928 Output.Append(
"=\"");
5938 foreach (
HtmlNode N2
in E.Children)
5941 Output.Append(
"</");
5942 Output.Append(E.Name);
5945 else if (E.IsEmptyElement)
5946 Output.Append(
"/>");
5949 Output.Append(
"></");
5950 Output.Append(E.Name);
5955 Output.Append(
XML.
Encode(Text.InlineText));
5960 char ch = (char)EntityUnicode.Code;
5965 Output.Append(
"<");
5969 Output.Append(
">");
5973 Output.Append(
""");
5977 Output.Append(
"'");
5981 Output.Append(
"&");
5991 switch (Entity.EntityName.ToLower())
5999 Output.Append(Entity.EntityName);
6013 private async Task Serialize(StringBuilder Content, IEnumerable<EmbeddedContent> Objects,
string ElementName,
XmppAddress Recipient)
6015 if (!(Objects is
null))
6024 Created = DateTime.Now,
6025 ContentId = Guid.NewGuid().ToString()
6030 Content.Append(
'<');
6031 Content.Append(ElementName);
6032 Content.Append(
" contentType='");
6037 Content.Append(
"' description='");
6043 Content.Append(
"' fileName='");
6049 Content.Append(
"' name='");
6055 Content.Append(
"' id='");
6059 Content.Append(
"' cid='");
6062 Content.Append(
"' size='");
6065 Content.Append(
"'/>");
6070 private async Task GetMailContent(
object Sender,
IqEventArgs e)
6076 if (Content is
null)
6090 if (!
string.IsNullOrEmpty(ContentType) &&
string.Compare(Content.
ContentType, ContentType,
true) != 0)
6097 LinkedList<MultipartContent> ToProcess =
new LinkedList<MultipartContent>();
6100 while (Data is
null && !(ToProcess.First is
null))
6103 ToProcess.RemoveFirst();
6107 if (
string.Compare(Obj.
ContentType, ContentType,
true) == 0)
6109 Data = Obj.TransferDecoded ?? Obj.
Raw;
6141 StringBuilder Xml =
new StringBuilder();
6143 Xml.Append(
"<content type='");
6145 Xml.Append(
"' xmlns='");
6146 Xml.Append(MailNamespace);
6153 Xml.Append(Convert.ToBase64String(Data));
6154 Xml.Append(
"</content>");
6160 private async Task DeleteMailContent(
object Sender,
IqEventArgs e)
6165 if (Content is
null)
6210 return await this.smtpServer.SendMessage(From, To, Subject,
new EmbeddedContent[]
6214 ContentType =
"text/html; charset=utf-8",
6215 Raw = Encoding.UTF8.GetBytes(HTML)
6219 ContentType =
"text/plain; charset=utf-8",
6220 Raw = Encoding.UTF8.GetBytes(PlainText)
6224 ContentType =
"text/markdown; charset=utf-8",
6225 Raw = Encoding.UTF8.GetBytes(Markdown)
6232 #region Service Discovery
6241 return this.ServiceDiscoveryAsync(To,
string.Empty);
6252 StringBuilder Xml =
new StringBuilder();
6253 bool CacheResponse =
string.IsNullOrEmpty(Node) && (
string.IsNullOrEmpty(To) || this.IsServerDomain(To,
true));
6254 TaskCompletionSource<ServiceDiscoveryResult> Result =
new TaskCompletionSource<ServiceDiscoveryResult>();
6256 Xml.Append(
"<query xmlns='");
6257 Xml.Append(DiscoveryNamespace);
6259 if (!
string.IsNullOrEmpty(Node))
6261 Xml.Append(
"' node='");
6267 await this.SendIqRequest(
"get", this.domainAddress,
new XmppAddress(To),
string.Empty,
6272 Dictionary<string, bool> Features = new Dictionary<string, bool>();
6273 List<Identity> Identities = new List<Identity>();
6275 foreach (XmlNode N in e.Response.ChildNodes)
6277 if (N.LocalName ==
"query")
6279 foreach (XmlNode N2 in N.ChildNodes)
6281 switch (N2.LocalName)
6284 Identities.Add(new Identity((XmlElement)N2));
6288 Features[XML.Attribute((XmlElement)N2,
"var")] = true;
6295 Result.TrySetResult(new ServiceDiscoveryResult(Identities.ToArray(), Features));
6297 else if (
string.IsNullOrEmpty(e.ErrorText))
6298 Result.TrySetException(
new Exception(
"Unable to perform service discovery."));
6300 Result.TrySetException(
new Exception(e.ErrorText));
6302 return Task.CompletedTask;
6306 return await Result.Task;
6315 return this.ServiceItemsDiscoveryAsync(To,
string.Empty);
6325 StringBuilder Xml =
new StringBuilder();
6326 TaskCompletionSource<Item[]> Result =
new TaskCompletionSource<Item[]>();
6328 Xml.Append(
"<query xmlns='");
6329 Xml.Append(DiscoveryItemsNamespace);
6331 if (!
string.IsNullOrEmpty(Node))
6333 Xml.Append(
"' node='");
6339 await this.SendIqRequest(
"get", this.domainAddress,
new XmppAddress(To),
6340 string.Empty, Xml.
ToString(), (Sender, e) =>
6344 List<Item> Items = new List<Item>();
6346 foreach (XmlNode N in e.Response.ChildNodes)
6348 if (N.LocalName ==
"query")
6350 foreach (XmlNode N2 in N.ChildNodes)
6352 if (N2.LocalName ==
"item")
6353 Items.Add(new Item((XmlElement)N2));
6358 Result.TrySetResult(Items.ToArray());
6360 else if (
string.IsNullOrEmpty(e.ErrorText))
6361 Result.TrySetException(
new Exception(
"Unable to perform service items discovery."));
6363 Result.TrySetException(
new Exception(e.ErrorText));
6365 return Task.CompletedTask;
6369 return await Result.Task;
6374 #region Finding components
6386 lock (this.services)
6392 string BareJid = GetBareJID(Jid);
6393 int i = BareJid.IndexOf(
'@');
6394 string Domain = BareJid.
Substring(i + 1);
6397 string Result =
null;
6403 Item[] Items = await this.ServiceItemsDiscoveryAsync(Domain);
6407 e = await this.ServiceDiscoveryAsync(
Component.JID);
6416 if (!
string.IsNullOrEmpty(Result))
6418 lock (this.services)
6420 this.services[Key] = Result;
6429 #region Push Notification
6433 private async Task NewTokenHandler(
object Sender,
IqEventArgs e)
6443 if (!this.IsServerDomain(e.
From.
Domain,
true))
6445 await e.
IqErrorForbidden(e.
To,
"Push Forwarding service only available for clients on broker.",
"en");
6462 if (
string.IsNullOrEmpty(Token))
6469 DateTime TP = DateTime.UtcNow;
6471 if (TokenObj is
null)
6484 tokens[BareJid] = TokenObj;
6490 TokenObj.Token = Token;
6491 TokenObj.Service = Service;
6493 TokenObj.Updated = TP;
6513 tokens[BareJid] = Token;
6520 #region Remove Token
6522 private async Task RemoveTokenHandler(
object Sender,
IqEventArgs e)
6532 if (!this.IsServerDomain(e.
From.
Domain,
true))
6534 await e.
IqErrorForbidden(e.
To,
"Push Forwarding service only available for clients on broker.",
"en");
6539 if (TokenObj is
null)
6545 tokens.Remove(BareJid);
6555 private async Task ClearRulesHandler(
object Sender,
IqEventArgs e)
6565 if (!this.IsServerDomain(e.
From.
Domain,
true))
6567 await e.
IqErrorForbidden(e.
To,
"Push Forwarding service only available for clients on broker.",
"en");
6572 rules.Remove(RuleKey(Rule));
6584 StringBuilder sb =
new StringBuilder();
6590 sb.Append(LocalName);
6592 sb.Append(Namespace);
6594 return sb.ToString();
6601 private async Task AddRuleHandler(
object Sender,
IqEventArgs e)
6611 if (!this.IsServerDomain(e.
From.
Domain,
true))
6613 await e.
IqErrorForbidden(e.
To,
"Push Forwarding service only available for clients on broker.",
"en");
6622 string PatternMatchingScript =
null;
6623 string ContentScript =
null;
6625 foreach (XmlNode N
in e.
Query.ChildNodes)
6627 if (N is XmlElement E && E.NamespaceURI == MessagePushNamespace)
6629 switch (E.LocalName)
6631 case "PatternMatching":
6632 PatternMatchingScript = E.InnerText.Trim();
6638 if (!CheckExpressionSafe(Exp, out
ScriptNode Prohibited))
6640 await e.
IqErrorForbidden(e.
To,
"Pattern Matching Script contains prohibited elements: " +
6641 Prohibited?.SubExpression,
"en");
6654 ContentScript = E.InnerText.Trim();
6660 if (!CheckExpressionSafe(Exp, out
ScriptNode Prohibited))
6663 Prohibited?.SubExpression,
"en");
6689 LocalName = LocalName,
6690 Namespace = Namespace,
6693 MessageVariable = MessageVariable,
6694 PatternMatchingScript = PatternMatchingScript,
6695 ContentScript = ContentScript
6700 rules[RuleKey(Rule)] = Rule;
6704 Rule.Channel = Channel;
6705 Rule.MessageVariable = MessageVariable;
6706 Rule.PatternMatchingScript = PatternMatchingScript;
6707 Rule.ContentScript = ContentScript;
6715 private readonly
static Assembly scriptContent = typeof(
GraphEncoder).Assembly;
6716 private readonly
static Assembly[] prohibitedAssemblies =
new Assembly[]
6720 typeof(
WhoIs).Assembly,
6735 return CheckExpressionSafe(
Expression,
false,
false,
false, out Prohibited);
6748 bool AllowCustomFunctions, out
ScriptNode Prohibited)
6755 Assembly Assembly = Node.GetType().Assembly;
6757 foreach (Assembly
A in prohibitedAssemblies)
6759 if (
A.FullName == Assembly.FullName)
6761 if (A == scriptContent &&
6762 (Node is Script.Content.Functions.Duration ||
6763 Node.GetType().Namespace == typeof(Utf8Encode).Namespace))
6773 if ((Node is
NamedMember && !AllowNamedMembers) ||
6781 (Node is
Error && !AllowError))
6791 Prohibited = Prohibited2;
6804 string LocalName,
string Namespace)
6806 string Key = RuleKey(BareJid,
MessageType, LocalName, Namespace);
6825 private async Task RemoveRuleHandler(
object Sender,
IqEventArgs e)
6835 if (!this.IsServerDomain(e.
From.
Domain,
true))
6837 await e.
IqErrorForbidden(e.
To,
"Push Forwarding service only available for clients on broker.",
"en");
6853 rules.Remove(RuleKey(Rule));
string Content
CDATA Content
string Name
Attribute name.
string Value
Attribute value.
static string GetBody(string Html)
Extracts the contents of the BODY element in a HTML string.
Body Body
First BODY element of document, if found, null otherwise.
Base class for all HTML elements.
static string EntityToCharacter(string Entity)
Converts an HTML entity into a character.
HTML Entity, as a unicode number string.
Base class for all HTML nodes.
Static class managing encoding and decoding of internet content.
static Task< object > DecodeAsync(string ContentType, byte[] Data, Encoding Encoding, KeyValuePair< string, string >[] Fields, Uri BaseUri)
Decodes an object.
Contains a markdown document. This markdown document class supports original markdown,...
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
Task< string > GenerateMarkdown()
Generates Markdown from the markdown text.
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,...
Represents alternative versions of the same content, encoded with multipart/alternative
Represents content embedded in other content.
string FileName
Filename of embedded object.
ContentDisposition Disposition
Disposition of embedded object.
string Name
Name of embedded object.
string Description
Content-Description of embedded object, if defined.
string ContentType
Content-Type of embedded object.
object Decoded
Decoded body of embedded object. ContentType defines how TransferDecoded is transformed into Decoded.
byte[] TransferDecoded
Transformed body of embedded object. TransferEncoding defines how Raw is transformed into TransferDec...
byte[] Raw
Raw, untrasnformed body of embedded object.
string ID
Content-ID of embedded object, if defined.
Abstract base class for multipart content
EmbeddedContent[] Content
Embedded content.
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static string HtmlValueEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe or the quote.
static string Encode(string s)
Encodes a string for use in XML.
static string HtmlAttributeEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe.
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
Contains statistical information about one item.
void Bind()
Binds to a TcpClient that was already connected when provided to the constructor.
void Continue()
Continues reading from the socket, if paused in an event handler.
Simple base class for classes implementing communication protocols.
Task Information(string Comment)
Called to inform the viewer of something.
DNS resolver, as defined in:
static async Task< string[]> LookupMailExchange(string DomainName)
Looks up the Mail Exchanges related to a given domain name.
static Task< SRV > LookupServiceEndpoint(string DomainName, string ServiceName, string Protocol)
Looks up a service endpoint for a domain. If multiple are available, an appropriate one is selected a...
string TargetHost
Target Host
Base class of all HTTP Exceptions.
Implements an HTTP server.
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
const int DefaultHttpPort
Default HTTP Port (80).
const int DefaultHttpsPort
Default HTTPS port (443).
Module that controls the life cycle of communication.
static bool Stopping
If the system is stopping.
Client Connection event argument.
Event arguments for SMTP Message events.
SmtpMessage Message
Message object
Represents one message received over SMTP
string MessageID
Message-ID.
object DecodedBody
Decoded body. ContentType defines how TransformedBody is transformed into DecodedBody.
DateTimeOffset? Date
Date of message, if defined
MailAddress FromMail
From address, as specified by the client to initiate mail transfer.
MailAddress FromHeader
From address, as specified in the mail headers.
Priority Priority
Priority of message
EmbeddedContent[] Attachments
Any attachments, if specified.
KeyValuePair< string, string >[] AllHeaders
All mail headers provided by client.
string ContentType
Content Type of message, if defined. Affects how TransformedBody is transformed into DecodedBody.
string Subject
Subject of message, if defined
EmbeddedContent[] InlineObjects
Any inline objects, if specified.
MailAddress Sender
Sender, as specified in the mail headers.
byte[] UntransformedBody
Raw, untrasnformed body of message.
Implements a simple SMTP Server, as defined in:
const int DefaultSmtpPort
Default SMTP Port (25).
Event arguments for connection events.
Sniffer that stores events in memory.
Outputs sniffed data to an XML file.
string FileName
File Name.
string Transform
Transform to use.
Implements a text-based TCP Client, by using the thread-safe full-duplex BinaryTcpClient.
Component managing accounts.
Client Connection event argument.
Abstract base class for XMPP client connections
CaseInsensitiveString UserName
User name
CaseInsensitiveString BareJid
Bare JID
const string StreamNamespace
http://etherx.jabber.org/streams
Base class for components.
CaseInsensitiveString Subdomain
Subdomain name.
string Name
Component name.
virtual void Dispose()
IDisposable.Dispose
async Task< bool > Message(string Type, string Id, XmppAddress To, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
Message stanza.
virtual bool SupportsAccounts
If the component supports accounts (true), or if the subdomain name is the only valid address.
Event arguments for IQ queries.
XmppAddress From
From address attribute
Task IqErrorNotAcceptable(XmppAddress From, string ErrorText, string Language)
Returns a not-acceptable error.
Task IqResult(string Xml, string From)
Returns a response to the current request.
Task IqErrorItemNotFound(XmppAddress From, string ErrorText, string Language)
Returns a item-not-found error.
XmlElement Query
Query element, if found, null otherwise.
Task IqErrorNotAllowed(XmppAddress From, string ErrorText, string Language)
Returns a not-allowed error.
XmppAddress To
To address attribute
async Task IqError(string ErrorType, string Xml, XmppAddress From, string ErrorText, string Language)
Returns an error response to the current request.
Task IqErrorBadRequest(XmppAddress From, string ErrorText, string Language)
Returns a bad-request error.
ISender Sender
Sender of stanza.
Task IqErrorForbidden(XmppAddress From, string ErrorText, string Language)
Returns a forbidden error.
string Id
ID of the request.
Maintains a set of IQ responses, for a limited time.
Event arguments for responses to IQ queries.
byte[] Content
Encoded content.
string ContentId
Content ID
CaseInsensitiveString BareJid
Bare JID
string ContentType
Content-Type
Web resource for requesting white-list authentication of a client.
Presence information event arguments.
string Type
Type attribute.
string Language
Language attribute.
object State
State object.
XmppAddress To
To attribute.
XmppAddress From
From attribute.
bool ResponseSent
If a response has been sent back to the sender.
DateTimeOffset Timestamp
Timestamp of reception.
Contains information about one persisted XML element.
string Xml
XML of stored element.
Push Notification settings.
string Namespace
Namespace of XML content element in message
string MessageType
Message tpye
CaseInsensitiveString BareJid
Bare JID of device
string LocalName
Local Name of XML content element in message
Push Notification settings.
int NrUpdates
Number of times object has been updated. (Created once only, without further updates = 1).
Server Connection event argument.
Contains information about an item of an entity.
override string ToString()
Object.ToString()
Service discovery result.
bool HasFeature(string Feature)
Checks if the remote entity supports a specific feature.
Manages the connection with an SMTP server.
Task< bool > RelayMessage(SmtpMessage Message, MailAddress Recipient)
Relays a mail message
Contains information about a stanza.
string Content
Literal XML content.
XmlElement StanzaElement
Stanza element.
Contains communication statistics.
Mainstains information about connectivity from a specific endpoint.
void EndpointConnected(IEndpoint Endpoint)
Call this method when the endpoint connects.
void EndpointDisconnected(IEndpoint Endpoint, long ConnectionTimeMilliseconds)
Call this method when the endpoint disconnects.
Mainstains information about connectivity from a specific s2s endpoint.
Contains information about one XMPP address.
override string ToString()
object.ToString()
bool IsBareJID
If the address is a Bare JID.
bool HasAccount
If the address has an account part.
bool IsEmpty
If the address is empty.
CaseInsensitiveString Domain
Domain
CaseInsensitiveString Address
XMPP Address
XmppAddress ToBareJID()
Returns the Bare JID as an XmppAddress object.
CaseInsensitiveString BareJid
Bare JID
static readonly XmppAddress Empty
Empty address.
CaseInsensitiveString Account
Account
bool IsFullJID
If the Address is a Full JID.
Class managing a connection.
Manages an XMPP server-to-server connection.
XmppS2sState State
Current state of connection.
Task< bool > Connect()
Connects to the server.
Connectivity information for a domain.
CaseInsensitiveString Host
Host name
S2sType Type
Type of S2S connection
bool TrustCertificate
If certificate should be trusted
CaseInsensitiveString Domain
Domain name
Task< bool > Message(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml, ISender Sender)
Message stanza.
const string DiscoveryItemsNamespace
http://jabber.org/protocol/disco#items (XEP-0030)
string ClientSnifferPath
If separate sniffers are to be created for each connected client, set this property to the file path ...
const string ExtendedAddressingNamespace
http://jabber.org/protocol/address (XEP-0033)
const string AbuseReportingNamespace
urn:xmpp:reporting:reason:abuse:0 (XEP-0377)
string GetRandomHexString(int NrBytes)
Generates a random hexadecimal string.
Task< DateTime?> GetEarliestLoginOpportunity(IClientConnection Connection)
Evaluates when a client is allowed to login.
async Task< bool > GetLastPresence(CaseInsensitiveString BareJid, EventHandlerAsync< PresenceEventArgs > Callback, object State)
Gets the last presence of a bare JID.
int[] OpenS2SPorts
S2S Ports successfully opened.
static async Task< XmppServer > Create(CaseInsensitiveString Domain, CaseInsensitiveString[] AlternativeDomains, int[] ClientToServerPorts, int[] ServerToServerPorts, X509Certificate ServerCertificate, bool EncryptionRequired, IXmppServerPersistenceLayer PersistenceLayer, SmtpServer SmtpServer, HttpServer HttpServer)
Creates an instance of an XMPP server.
static void RegisterRemoteDomain(CaseInsensitiveString RemoteDomain, string Host, int Port, bool TrustCertificate)
By default, remote domains are reached using DNS, and the default server-to-server port (5269) is use...
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsFeature)
Unregisters a message handler.
const string RosterNamespace
jabber:iq:roster (RFC 6121)
const string VCardNamespace
vcard-temp (XEP-0054)
static Scheduler Scheduler
Scheduler
const string BlockingCommandNamespace
urn:xmpp:blocking (XEP-0191)
void RegisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsFeature)
Registers an IQ-Set handler.
Task< bool > Presence(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml, ISender Sender)
Presence stanza.
EventHandlerAsync< PresenceEventArgs > OnPresenceLocalSender
If a local sender sends a presence stanza
IClientConnection[] GetClientConnections()
Get active client connections
static Task< XmppServer > Create(CaseInsensitiveString Domain, CaseInsensitiveString[] AlternativeDomains, int ClientToServerPort, int ServerToServerPort, X509Certificate ServerCertificate, bool EncryptionRequired, IXmppServerPersistenceLayer PersistenceLayer)
Creates an instance of an XMPP server.
int[] OpenC2SPorts
C2S Ports successfully opened.
const string DiscoveryNamespace
http://jabber.org/protocol/disco#info (XEP-0030)
void UpdateCertificate(X509Certificate ServerCertificate)
Updates the server certificate
const string MessagePushNamespace
http://waher.se/Schema/PushNotification.xsd
CommunicationLayer S2sSniffers
Sniffers for XMPP S2S communication.
Task< IqResultEventArgs > IqRequest(string Type, string From, string To, string Language, string ContentXml)
Sends an IQ stanza to a recipient.
S2sEndpointStatistics[] GetServerConnectionStatistics()
Gets S2S connection statistics.
EventHandlerAsync< ClientConnectionEventArgs > ClientConnectionUpdated
Event raised when a client connection has been updated.
Task< bool > SendMessage(string Type, string Id, string From, string To, string Language, string ContentXml)
Sends a Message stanza to a recipient.
const int DefaultConnectionBacklog
Default Connection backlog (10).
static void GetErrorInformation(Exception ex, out string Type, out string Xml)
Converts an Exception to an XMPP error message.
S2sEndpointStatistics GetS2sStatistics(CaseInsensitiveString Endpoint, string Type)
Gets available S2S Endpoint statistics for an endpoint.
bool TryGetClientConnections(string BareJID, out IClientConnection[] Connections)
Tries to get available connections for a given client.
const string SaslNamespace
urn:ietf:params:xml:ns:xmpp-sasl
Task< Item[]> ServiceItemsDiscoveryAsync(string To)
Performs a service items discovery request
static byte[] GetRandomNumbers(int NrBytes)
Generates a set of random numbers.
virtual Task< bool > MessageError(string Id, XmppAddress To, XmppAddress From, Exception ex)
Sends a message error stanza.
virtual async Task< bool > IqError(string Id, XmppAddress To, XmppAddress From, string ErrorXml)
Sends an IQ error stanza.
bool TryGetClientConnection(string FullJID, out IClientConnection Connection)
Tries to get an active client connection.
async Task< bool > SendMessage(string Type, string Id, XmppAddress From, XmppAddress To, string Language, string ContentXml)
Sends a Message stanza to a recipient.
async Task< bool > Message(string Type, string Id, XmppAddress To, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
Message stanza.
virtual async Task< bool > PresenceError(string Id, XmppAddress To, XmppAddress From, Exception ex)
Sends a presence error stanza.
Task< ServiceDiscoveryResult > ServiceDiscoveryAsync(string To)
Performs a service discovery request
async Task< bool > IQ(string Type, string Id, XmppAddress To, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
IQ stanza.
virtual Task< bool > Message(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml)
Sends a message stanza.
async Task< IqResultEventArgs > IqRequest(string Type, XmppAddress From, XmppAddress To, string Language, string ContentXml)
Sends an IQ stanza to a recipient.
async Task< bool > Presence(string Type, string Id, XmppAddress To, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
Presence stanza.
const string ReportingNamespace
urn:xmpp:reporting:0 (XEP-0377)
const string BlockingCommandErrorNamespace
urn:xmpp:blocking:errors (XEP-0191)
const string ContentNamespace
urn:xmpp:content
Task< bool > IQ(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml, ISender Sender)
IQ stanza.
virtual async Task< bool > Presence(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml)
Sends a presence stanza.
static void RegisterRemoteDomain(CaseInsensitiveString RemoteDomain, CaseInsensitiveString ServerDomain, string Host, int Port, bool TrustCertificate)
By default, remote domains are reached using DNS, and the default server-to-server port (5269) is use...
Task< bool > SendIqRequest(string Type, string From, string To, string Language, string ContentXml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ stanza to a recipient.
const string DataFormsNamespace
jabber:x:data (XEP-0004)
EventHandlerAsync< ServerConnectionEventArgs > ServerConnectionAdded
Event raised when a server connection has been added.
const int MaxNameLength
1000
const string OfflineMessagesNamespace
msgoffline (XEP-0160)
static async Task< PushNotificationToken > TryGetPushNotificationToken(CaseInsensitiveString BareJid)
Tries to get a push notification token for a client, if one exists.
static bool IsValidUserName(string UserName)
Checks if a user name contains invalid characters.
CaseInsensitiveString[] RemoteConnections
Current remote connections.
const string AlternativesNamespace
http://waher.se/Schema/AlternativeNames.xsd
bool TryGetS2sStatistics(CaseInsensitiveString Endpoint, out S2sEndpointStatistics Stat)
Tries to get available S2S Endpoint statistics for an endpoint.
int NrServerConnections
Number of server connections.
bool Disposed
If the server has been disposed.
const string SoftwareVersionNamespace
jabber:iq:version (XEP-0092)
string DomainSnifferPath
If separate sniffers are to be created for each federated domain, set this property to the file path ...
const int DefaultBufferSize
Default buffer size (16384).
const string PrivateXmlStorageNamespace
jabber:iq:private (XEP-0049)
CommunicationLayer C2sSniffers
Sniffers for XMPP C2S communication.
bool UnregisterComponent(IComponent Component)
Unregisters a component from the server.
const string PingNamespace
urn:xmpp:ping (XEP-0199)
bool IsServerDomain(CaseInsensitiveString Domain, bool IncludeAlternativeDomains)
Checks if a domain is the server domain, or optionally, an alternative domain.
IComponent[] Components
Registered components
X509Certificate ServerCertificate
Server domain certificate.
bool EncryptionRequired
If C2S encryption is requried.
bool UnregisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsFeature)
Unregisters an IQ-Get handler.
string GetDialbackKey(string ReceivingServer, string OriginatingServer, string ReceivingStreamId)
Gets a dialback key, calculated according to XEP-0185: https://xmpp.org/extensions/xep-0185....
static Task< XmppServer > Create(CaseInsensitiveString Domain, CaseInsensitiveString[] AlternativeDomains, int[] ClientToServerPorts, int[] ServerToServerPorts, X509Certificate ServerCertificate, bool EncryptionRequired, IXmppServerPersistenceLayer PersistenceLayer)
Creates an instance of an XMPP server.
void RegisterIqGetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool PublishNamespaceAsFeature)
Registers an IQ-Get handler.
const int DefaultS2sPort
Default Server-to-Server Port (5269).
CaseInsensitiveString Domain
Domain name.
static bool CheckExpressionSafe(Expression Expression, bool AllowNamedMembers, bool AllowError, bool AllowCustomFunctions, out ScriptNode Prohibited)
Checks if an expression is safe to execute (if it comes from an external source).
const string TimeNamespace
urn:xmpp:time (XEP-0202)
const int DefaultC2sPort
Default Client-to-Server Port (5222).
static bool CheckExpressionSafe(Expression Expression, out ScriptNode Prohibited)
Checks if an expression is safe to execute (if it comes from an external source).
async Task< CaseInsensitiveString > FindComponentAsync(CaseInsensitiveString Jid, CaseInsensitiveString Feature)
Finds a component having a specific feature, servicing a JID.
async Task< bool > SendIqRequest(string Type, XmppAddress From, XmppAddress To, string Language, string ContentXml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ stanza to a recipient.
const string RegisterNamespace
jabber:iq:register (XEP-0077)
const string StanzaNamespace
urn:ietf:params:xml:ns:xmpp-stanzas (RFC 6120)
bool TryGetS2sEndpoint(string RemoteDomain, out IS2SEndpoint Endpoint)
Tries to get a server-to-server connection state object.
void Dispose()
IDisposable.Dispose
static Task< XmppServer > Create(CaseInsensitiveString Domain, CaseInsensitiveString[] AlternativeDomains, X509Certificate ServerCertificate, bool EncryptionRequired, IXmppServerPersistenceLayer PersistenceLayer)
Creates an instance of an XMPP server.
EventHandlerAsync< ClientConnectionEventArgs > ClientConnectionRemoved
Event raised when a client connection has been removed.
virtual async Task< bool > IqResult(string Id, XmppAddress To, XmppAddress From, string ResultXml)
Sends an IQ result stanza.
Statistics.CommunicationStatistics GetCommunicationStatisticsSinceLast()
Gets communication statistics since last call.
const string DelayedDeliveryNamespace
urn:xmpp:delay (XEP-0203)
static async Task< S2SRec > GetDomain(CaseInsensitiveString DomainOrSubdomain)
Gets information about a domain.
const string MailNamespace
urn:xmpp:smtp
const int MaxGroupLength
1000
EventHandlerAsync< ClientConnectionEventArgs > ClientConnectionAdded
Event raised when a client connection has been added.
const string OAuth1FormSignatureNamespace
urn:xmpp:xdata:signature:oauth1 (XEP-0348)
EventHandlerAsync< ServerConnectionEventArgs > ServerConnectionRemoved
Event raised when a server connection has been removed.
static async Task< PushNotificationRule > TryGetPushNotificationRule(CaseInsensitiveString BareJid, string MessageType, string LocalName, string Namespace)
Tries to get a push notification token for a client, if one exists.
const string StreamsNamespace
urn:ietf:params:xml:ns:xmpp-streams
string NewId(int NrBytes)
Generates a new ID.
const string AvatarStorageNamespace
storage:client:avatar (XEP-0008)
bool UnregisterIqSetHandler(string LocalName, string Namespace, EventHandlerAsync< IqEventArgs > Handler, bool RemoveNamespaceAsFeature)
Unregisters an IQ-Set handler.
virtual async Task< string > IqError(string Id, XmppAddress To, XmppAddress From, Exception ex)
Sends an IQ error stanza.
EventHandlerAsync< ServerConnectionEventArgs > ServerConnectionUpdated
Event raised when a server connection has been updated.
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsFeature)
Registers a message handler.
async Task< Item[]> ServiceItemsDiscoveryAsync(string To, string Node)
Performs a service items discovery request
async Task ProcessMessage(SmtpMessage Message)
Processes an incoming SMTP message.
virtual async Task< bool > PresenceError(string Id, XmppAddress To, XmppAddress From, string ErrorXml)
Sends a presence error stanza.
async Task< bool > Presence(string Type, string Id, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
Presence stanza.
static CaseInsensitiveString GetBareJID(CaseInsensitiveString JID)
Gets the Bare JID from a JID, which may be a Full JID.
CaseInsensitiveString[] AlternativeDomains
Alternative domain names.
bool RegisterComponent(IComponent Component)
Registers a component with the server.
Accounts Accounts
Accounts
const string SpamReportingNamespace
urn:xmpp:reporting:reason:abuse:0 (XEP-0377)
async Task< bool > SendMailMessage(CaseInsensitiveString From, CaseInsensitiveString To, string Subject, string Markdown)
Sends a mail message
async Task< ServiceDiscoveryResult > ServiceDiscoveryAsync(string To, string Node)
Performs a service discovery request
S2sType
Domain connection type
async Task< Tuple< bool, IRecipient > > TryGetRecipient(XmppAddress To, XmppAddress From)
Tries to get the recipient of a stanza.
EventHandlerAsync< PresenceEventArgs > OnPresenceLocalRecipient
If a local recipient receives a presence stanza
int NrClientConnections
Number of client connections.
async Task< int > DeleteOldMailContent(DateTime OlderThan)
Deletes old mail content.
Base class for all stanza exceptions.
Represents a case-insensitive string.
static readonly CaseInsensitiveString Empty
Empty case-insensitive string
int Length
Gets the number of characters in the current CaseInsensitiveString object.
string LowerCase
Lower-case representation of the case-insensitive string.
int IndexOf(CaseInsensitiveString value, StringComparison comparisonType)
Reports the zero-based index of the first occurrence of the specified string in the current System....
static bool IsNullOrEmpty(CaseInsensitiveString value)
Indicates whether the specified string is null or an CaseInsensitiveString.Empty string.
int CompareTo(CaseInsensitiveString other)
Compares this instance with a specified System.CaseInsensitiveString object and indicates whether thi...
CaseInsensitiveString[] Split(params char[] separator)
Returns a string array that contains the substrings in this instance that are delimited by elements o...
override string ToString()
CaseInsensitiveString Substring(int startIndex, int length)
Retrieves a substring from this instance. The substring starts at a specified character position and ...
char[] ToCharArray(int startIndex, int length)
Copies the characters in a specified substring in this instance to a Unicode character array.
bool EndsWith(CaseInsensitiveString value, StringComparison comparisonType)
Determines whether the end of this string instance matches the specified string when compared using t...
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 async Task DeleteLazy(object Object)
Deletes an object in the database, if unlocked. If locked, object will be deleted at next opportunity...
static async Task InsertLazy(object Object)
Inserts an object into the database, if unlocked. If locked, object will be inserted at next opportun...
static async Task UpdateLazy(object Object)
Updates an object in the database, if unlocked. If locked, object will be updated at next opportunity...
static async Task Update(object Object)
Updates an object in the database.
static async Task Delete(object Object)
Deletes 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.
This filter selects objects that have a named field lesser or equal to a given value.
Implements an in-memory cache.
ValueType[] GetValues()
Gets all available values in the cache.
bool ContainsKey(KeyType Key)
Checks if a key is available in the cache.
void Dispose()
IDisposable.Dispose
int Count
Number of items in cache
bool Remove(KeyType Key)
Removes an item from the cache.
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
KeyType[] GetKeys()
Gets all available keys in the cache.
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
void Clear()
Clears the cache.
Event arguments for cache item removal events.
KeyType Key
Key of item that was removed.
ValueType Value
Value of item that was removed.
RemovedReason Reason
Reason for removing the item.
Static class that dynamically manages types and interfaces available in the runtime environment.
static Type[] NoTypes
Contains an empty array of types.
static object[] NoParameters
Contains an empty array of parameter values.
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
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.
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
void Dispose()
IDisposable.Dispose
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Generates a callback function based on script.
Creates a connection to an external MS SQL database.
Class managing a script expression.
bool ForAll(ScriptNodeEventHandler Callback, object State, bool DepthFirst)
Calls the callback method for all script nodes defined for the expression.
Defines a clickable fractal graph in the complex plane.
Matches a Full-Text-Search Index with a Database Collection.
Creates an object of a specific class. The first argument must evaluate to the type that is to be cre...
Destroys a value. If the function references a variable, the variable is also removed.
Extract the properties of a type or an object.
Removes a variable from the variables collection, without destroying its value.
Base class for all nodes in a parsed script tree.
Makes a WHOIS query regarding an IP address.
Named member Assignment operator.
Dynamic function call operator
Named method call operator.
Executes a SELECT statement against the object database.
ShellExecute(FileName,Arguments,WorkFolder)
Contains methods for simple hash calculations.
static string ComputeHMACSHA256HashString(byte[] Key, byte[] Data)
Computes the HMAC-SHA-256 hash of a block of binary data.
static byte[] ComputeHMACSHA1Hash(byte[] Key, byte[] Data)
Computes the HMAC-SHA-1 hash of a block of binary data.
static string BinaryToString(byte[] Data)
Converts an array of bytes to a string with their hexadecimal representations (in lower case).
static byte[] ComputeSHA256Hash(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
static string ComputeSHA1HashString(byte[] Data)
Computes the SHA-1 hash of a block of binary data.
Class that monitors login events, and help applications determine malicious intent....
static async void Success(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
async Task< DateTime?> GetEarliestLoginOpportunity(string RemoteEndpoint, string Protocol)
Checks when a remote endpoint can login.
static async void Fail(string Message, string UserName, string RemoteEndpoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a failed login attempt.
Task Information(string Comment)
Called to inform the viewer of something.
Task Exception(string Exception)
Called to inform the viewer of an exception state.
Interface for observable classes implementing communication protocols.
bool HasSniffers
If there are sniffers registered on the object.
ISniffer[] Sniffers
Registered sniffers.
void Add(ISniffer Sniffer)
Adds a sniffer to the node.
Interface for SMTP user accounts.
CaseInsensitiveString UserName
User Name
Interface for authentication mechanisms.
Task< bool?> AuthenticationRequest(string Data, ISaslServerSide Connection, ISaslPersistenceLayer PersistenceLayer)
Authentication request has been made.
bool Allowed(SslStream SslStream)
Checks if a mechanism is allowed during the current conditions.
Task Initialize()
Performs intitialization of the mechanism. Can be used to set static properties that will be used thr...
string Name
Name of the mechanism.
string Protocol
String representing protocol being used.
void ResetState(bool Authenticated)
Resets the state machine.
CaseInsensitiveString UserName
User name
string RemoteEndpoint
Remote endpoint.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Interface for XMPP user accounts.
Interface for client connections.
Task< bool > BeginWrite(string Xml, EventHandlerAsync< DeliveryEventArgs > Callback, object State)
Writes XML to the client.
PresenceEventArgs LastPresence
Last presence received.
XmppAddress Address
Full Address
Task< bool > SaslErrorInvalidMechanism()
Returns a Invalid Mechanism SASL error.
Task< bool > SaslErrorMechanismTooWeak()
Returns a Mechanism too weak SASL error.
Task< bool > SaslErrorTemporaryAuthFailure(string Message, string Language)
Returns a Authentication Failure SASL error.
CaseInsensitiveString FullJid
Full JID
XmppConnectionState State
Connection state.
bool WantsBlockList
If connection is interested in block list events.
void SetMechanism(IAuthenticationMechanism Mechanism)
Sets the authentication mechanism for the connection.
XmppAddress BareAddress
Bare Address
CaseInsensitiveString BareJid
Bare JID
Task< bool > StreamErrorInvalidXml()
Returns a Invalid XML stream error.
Interface for components.
Task DisposeAsync()
Disposes the connection
string Type
Type of endpoint
Interface for recipients of stanzas.
Task< bool > IQ(string Type, string Id, XmppAddress To, XmppAddress From, string Language, Stanza Stanza, ISender Sender)
IQ stanza.
Interface for roster items.
Interface for XMPP S2S endpoints
CaseInsensitiveString RemoteDomain
Connection to domain.
Interface for senders of stanzas.
Task< bool > Message(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml)
Message stanza.
Task< bool > Presence(string Type, string Id, XmppAddress To, XmppAddress From, string Language, string ContentXml)
Presence stanza.
Task< string > IqError(string Id, XmppAddress To, XmppAddress From, Exception ex)
Sends an IQ Error stanza.
Task< bool > IqResult(string Id, XmppAddress To, XmppAddress From, string ResultXml)
Sends an IQ Result stanza.
Interface for XMPP Server persistence layers. The persistence layer should implement caching.
Task< byte[]> GetDialbackSecret()
Gets the Dialback secret, as defined in XEP-0185.
ContentDisposition
Content disposition
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
BinaryPresentationMethod
How binary data is to be presented.
PushMessagingService
Push messaging service used.
ClientType
Type of client requesting notification.
XmppConnectionState
State of XMPP connection.
XmppS2sState
State of XMPP connection.
SubscriptionStatus
Roster item subscription status enumeration.
BlockingReason
Reason for blocking an account.
MessageType
Type of message received.
PendingSubscription
Pending subscription states.
RemovedReason
Reason for removing the item.
SearchMethod
Method to traverse the expression structure
ContentType
DTLS Record content type.
Reason
Reason a token is not valid.