diff --git a/UWPX_UI/Controls/Chat/ChatDetailsControl.xaml.cs b/UWPX_UI/Controls/Chat/ChatDetailsControl.xaml.cs index 4d3fdd2aa..a7c4fe825 100644 --- a/UWPX_UI/Controls/Chat/ChatDetailsControl.xaml.cs +++ b/UWPX_UI/Controls/Chat/ChatDetailsControl.xaml.cs @@ -8,6 +8,8 @@ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; +using XMPP_API.Classes.Network.XML.Messages.Helper; +using XMPP_API.Classes.Network.XML.Messages.XEP_0313; namespace UWPX_UI.Controls.Chat { @@ -156,10 +158,13 @@ private async void Leave_mfo_Click(object sender, RoutedEventArgs e) await VIEW_MODEL.LeaveMucAsync(Chat); } - private void Test_mfo_Click(object sender, RoutedEventArgs e) + private async void Test_mfo_Click(object sender, RoutedEventArgs e) { if (!IsDummy) { + QueryFilter filter = new QueryFilter(); + filter.with(Chat.Chat.chatJabberId); + MessageResponseHelperResult result = await Chat.Client.GENERAL_COMMAND_HELPER.requestMamAsync(filter); } } diff --git a/XMPP_API/Classes/Consts.cs b/XMPP_API/Classes/Consts.cs index 95d5f0bac..3a361068e 100644 --- a/XMPP_API/Classes/Consts.cs +++ b/XMPP_API/Classes/Consts.cs @@ -89,9 +89,14 @@ public static class Consts // XEP-0313 (Message Archive Management) public const string XML_XEP_0313_TMP_NAMESPACE = "urn:xmpp:mam:tmp"; public const string XML_XEP_0313_NAMESPACE = "urn:xmpp:mam:2"; + public const string XML_XEP_0313_EXTENDED_NAMESPACE = "urn:xmpp:mam:2#extended"; // XEP-0359 (Unique and Stable Stanza IDs) public const string XML_XEP_0359_NAMESPACE = "urn:xmpp:sid:0"; // XEP-0199 (XMPP Ping) public const string XML_XEP_0199_NAMESPACE = "urn:xmpp:ping"; + // XEP-0297 (Stanza Forwarding) + public const string XML_XEP_0297_NAMESPACE = "urn:xmpp:forward:0"; + // XEP-0059 (Result Set Management) + public const string XML_XEP_0059_NAMESPACE = "http://jabber.org/protocol/rsm"; } } diff --git a/XMPP_API/Classes/GeneralCommandHelper.cs b/XMPP_API/Classes/GeneralCommandHelper.cs index d7d89c1f9..526a3297d 100644 --- a/XMPP_API/Classes/GeneralCommandHelper.cs +++ b/XMPP_API/Classes/GeneralCommandHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Logging; using XMPP_API.Classes.Network; @@ -7,6 +8,7 @@ using XMPP_API.Classes.Network.XML.Messages.XEP_0030; using XMPP_API.Classes.Network.XML.Messages.XEP_0085; using XMPP_API.Classes.Network.XML.Messages.XEP_0280; +using XMPP_API.Classes.Network.XML.Messages.XEP_0313; using XMPP_API.Classes.Network.XML.Messages.XEP_0357; namespace XMPP_API.Classes @@ -241,6 +243,36 @@ public async Task> disableMessageCarbonsA return await helper.startAsync(msg); } + /// + /// Sends a to the server and requests the MAM archive. + /// + /// The result of the request. + public async Task> requestMamAsync(QueryFilter filter) + { + QueryArchiveMessage msg = new QueryArchiveMessage(filter); + List results = new List(); + Predicate predicate = (x) => + { + if (x is QueryArchiveResultMessage result && string.Equals(result.QUERY_ID, msg.QUERY_ID)) + { + results.Add(result); + return false; + } + return x is QueryArchiveFinishMessage fin && string.Equals(fin.ID, msg.ID) && string.Equals(fin.QUERY_ID, msg.QUERY_ID); + }; + AsyncMessageResponseHelper helper = new AsyncMessageResponseHelper(CONNECTION, predicate) + { + matchId = false + }; + MessageResponseHelperResult finResult = await helper.startAsync(msg); + MamResult mamResult = null; + if (finResult.STATE == MessageResponseHelperResultState.SUCCESS) + { + mamResult = new MamResult(finResult.RESULT as QueryArchiveFinishMessage, results); + } + return new MessageResponseHelperResult(finResult.STATE, mamResult); + } + #endregion #region --Misc Methods (Private)-- diff --git a/XMPP_API/Classes/Network/XML/MessageParser2.cs b/XMPP_API/Classes/Network/XML/MessageParser2.cs index 1059669dc..cb2672244 100644 --- a/XMPP_API/Classes/Network/XML/MessageParser2.cs +++ b/XMPP_API/Classes/Network/XML/MessageParser2.cs @@ -16,6 +16,7 @@ using XMPP_API.Classes.Network.XML.Messages.XEP_0198; using XMPP_API.Classes.Network.XML.Messages.XEP_0199; using XMPP_API.Classes.Network.XML.Messages.XEP_0249; +using XMPP_API.Classes.Network.XML.Messages.XEP_0313; using XMPP_API.Classes.Network.XML.Messages.XEP_0336; using XMPP_API.Classes.Network.XML.Messages.XEP_0363; using XMPP_API.Classes.Network.XML.Messages.XEP_0384; @@ -352,9 +353,15 @@ private List parseMessageInternal(ref string msg) } else { + // XEP-0313 (Message Archive Management): + if (XMLUtils.getChildNode(n, "fin", Consts.XML_XMLNS, Consts.XML_XEP_0313_NAMESPACE) != null) + { + messages.Add(new QueryArchiveFinishMessage(n)); + fondNode = true; + break; + } // XEP-0363 (HTTP File Upload) slot response: - XmlNode slotNode = XMLUtils.getChildNode(n, "slot", Consts.XML_XMLNS, Consts.XML_XEP_0363_NAMESPACE); - if (slotNode != null) + if (XMLUtils.getChildNode(n, "slot", Consts.XML_XMLNS, Consts.XML_XEP_0363_NAMESPACE) != null) { messages.Add(new HTTPUploadResponseSlotMessage(n)); fondNode = true; @@ -488,6 +495,11 @@ private void parseMessageMessage(List messages, XmlNode n, Carb { messages.Add(new DeliveryReceiptMessage(n)); } + // XEP-0313 (Message Archive Management): + else if (XMLUtils.getChildNode(n, "result", Consts.XML_XMLNS, Consts.XML_XEP_0313_NAMESPACE) != null) + { + messages.Add(new QueryArchiveResultMessage(n)); + } // XEP-0249 (Direct MUC Invitations): else if (XMLUtils.getChildNode(n, "x", Consts.XML_XMLNS, Consts.XML_XEP_0249_NAMESPACE) != null) { diff --git a/XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResult.cs b/XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResult.cs index ab5dea789..862791ead 100644 --- a/XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResult.cs +++ b/XMPP_API/Classes/Network/XML/Messages/Helper/MessageResponseHelperResult.cs @@ -1,6 +1,6 @@ namespace XMPP_API.Classes.Network.XML.Messages.Helper { - public class MessageResponseHelperResult where T : AbstractAddressableMessage + public class MessageResponseHelperResult where T : class { //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ #region --Attributes-- diff --git a/XMPP_API/Classes/Network/XML/Messages/MessageMessage.cs b/XMPP_API/Classes/Network/XML/Messages/MessageMessage.cs index f971cfc65..0b791d6c4 100644 --- a/XMPP_API/Classes/Network/XML/Messages/MessageMessage.cs +++ b/XMPP_API/Classes/Network/XML/Messages/MessageMessage.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Xml; using System.Xml.Linq; @@ -98,12 +99,7 @@ public MessageMessage(XmlNode node, CarbonCopyType ccType) : base(node.Attribute XmlNode delayNode = XMLUtils.getChildNode(node, "delay", Consts.XML_XMLNS, Consts.XML_XEP_0203_NAMESPACE); if (delayNode != null) { - XmlAttribute stamp = XMLUtils.getAttribute(delayNode, "stamp"); - if (stamp != null) - { - DateTimeParserHelper parserHelper = new DateTimeParserHelper(); - delay = parserHelper.parse(stamp.Value); - } + parseDelay(delayNode); } else { @@ -186,13 +182,11 @@ public override XElement toXElement() } // XEP-0359 (Unique and Stable Stanza IDs): - if (ID != null) - { - XNamespace ns = Consts.XML_XEP_0359_NAMESPACE; - XElement originId = new XElement(ns + "origin-id", MESSAGE); - originId.Add(new XAttribute("id", ID)); - msgNode.Add(originId); - } + Debug.Assert(ID != null); + XNamespace sid_ns = Consts.XML_XEP_0359_NAMESPACE; + XElement originId = new XElement(sid_ns + "origin-id", MESSAGE); + originId.Add(new XAttribute("id", ID)); + msgNode.Add(originId); // XEP-0203 (Delayed Delivery): if (delay != DateTime.MinValue) @@ -227,6 +221,20 @@ public void addDelay(DateTime date) delay = date; } + /// + /// Parses a XEP-0203 (Delayed Delivery). + /// + public void parseDelay(XmlNode delayNode) + { + Debug.Assert(!(delayNode is null)); + XmlAttribute stamp = XMLUtils.getAttribute(delayNode, "stamp"); + if (stamp != null) + { + DateTimeParserHelper parserHelper = new DateTimeParserHelper(); + delay = parserHelper.parse(stamp.Value); + } + } + #endregion #region --Misc Methods (Private)-- diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0059/Set.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0059/Set.cs new file mode 100644 index 000000000..46c6d71e6 --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0059/Set.cs @@ -0,0 +1,120 @@ +using System.Xml; +using Logging; + +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0059 +{ + public class Set + { + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + public readonly string AFTER; + public readonly string BEFORE; + public readonly uint? COUNT; + public readonly string FIRST; + public readonly uint? FIRST_INDEX; + public readonly uint? INDEX; + public readonly string LAST; + public readonly string MAX; + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + public Set(XmlNode answer) + { + XmlNode afterNode = XMLUtils.getChildNode(answer, "after"); + if (!(afterNode is null)) + { + AFTER = afterNode.InnerText; + } + + XmlNode beforeNode = XMLUtils.getChildNode(answer, "before"); + if (!(beforeNode is null)) + { + BEFORE = beforeNode.InnerText; + } + + XmlNode countNode = XMLUtils.getChildNode(answer, "count"); + if (!(countNode is null)) + { + if (uint.TryParse(countNode.InnerText, out uint count)) + { + COUNT = count; + } + else + { + Logger.Error("Failed to parse XEP-0313 SET count node value as uint: " + countNode.InnerText); + } + } + + XmlNode firstNode = XMLUtils.getChildNode(answer, "first"); + if (!(firstNode is null)) + { + FIRST = firstNode.InnerText; + string tmp = firstNode.Attributes["index"]?.Value; + if (!(tmp is null)) + { + if (uint.TryParse(tmp, out uint index)) + { + FIRST_INDEX = index; + } + else + { + Logger.Error("Failed to parse XEP-0313 SET first_index node value as uint: " + tmp); + } + } + } + + XmlNode indexNode = XMLUtils.getChildNode(answer, "index"); + if (!(indexNode is null)) + { + if (uint.TryParse(indexNode.InnerText, out uint index)) + { + INDEX = index; + } + else + { + Logger.Error("Failed to parse XEP-0313 SET index node value as uint: " + indexNode.InnerText); + } + } + + XmlNode lastNode = XMLUtils.getChildNode(answer, "last"); + if (!(lastNode is null)) + { + LAST = lastNode.InnerText; + } + + XmlNode maxNode = XMLUtils.getChildNode(answer, "max"); + if (!(maxNode is null)) + { + MAX = maxNode.InnerText; + } + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + + + #endregion + + #region --Misc Methods (Private)-- + + + #endregion + + #region --Misc Methods (Protected)-- + + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/MamResult.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/MamResult.cs new file mode 100644 index 000000000..a1ee12bbf --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/MamResult.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0313 +{ + public class MamResult + { + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + public readonly string FIRST; + public readonly string LAST; + public readonly uint INDEX; + public readonly uint COUNT; + public readonly bool COMPLETE; + public readonly List RESULTS; + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + public MamResult(QueryArchiveFinishMessage msg, List results) + { + if (!msg.COMPLETE) + { + Debug.Assert(string.IsNullOrEmpty(msg.RESULT_SET.FIRST)); + Debug.Assert(!(msg.RESULT_SET.FIRST_INDEX is null)); + Debug.Assert(string.IsNullOrEmpty(msg.RESULT_SET.LAST)); + + FIRST = msg.RESULT_SET.FIRST; + LAST = msg.RESULT_SET.LAST; + INDEX = (uint)msg.RESULT_SET.FIRST_INDEX; + } + else + { + COMPLETE = true; + } + Debug.Assert(!(msg.RESULT_SET.COUNT is null)); + COUNT = (uint)msg.RESULT_SET.COUNT; + + RESULTS = results; + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + + + #endregion + + #region --Misc Methods (Private)-- + + + #endregion + + #region --Misc Methods (Protected)-- + + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveFinishMessage.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveFinishMessage.cs new file mode 100644 index 000000000..34d0dcf1b --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveFinishMessage.cs @@ -0,0 +1,59 @@ +using System.Xml; +using XMPP_API.Classes.Network.XML.Messages.XEP_0059; + +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0313 +{ + public class QueryArchiveFinishMessage: IQMessage + { + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + public readonly Set RESULT_SET; + public readonly bool COMPLETE; + public readonly string QUERY_ID; + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + public QueryArchiveFinishMessage(XmlNode answer) : base(answer) + { + XmlNode finNode = XMLUtils.getChildNode(answer, "fin", Consts.XML_XMLNS, Consts.XML_XEP_0313_NAMESPACE); + if (!(finNode is null)) + { + QUERY_ID = finNode.Attributes["queryid"]?.Value; + COMPLETE = XMLUtils.tryParseToBool(finNode.Attributes["complete"]?.Value); + XmlNode setNode = XMLUtils.getChildNode(finNode, "set", Consts.XML_XMLNS, Consts.XML_XEP_0059_NAMESPACE); + if (!(setNode is null)) + { + RESULT_SET = new Set(setNode); + } + } + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + + + #endregion + + #region --Misc Methods (Private)-- + + + #endregion + + #region --Misc Methods (Protected)-- + + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveMessage.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveMessage.cs index 9dcd3bd83..3d853d815 100644 --- a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveMessage.cs +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveMessage.cs @@ -1,16 +1,22 @@ using System.Xml.Linq; -namespace XMPP_API.Classes.Network.XML.Messages.XEP_313 +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0313 { public class QueryArchiveMessage: IQMessage { //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ #region --Attributes-- + public readonly string QUERY_ID; + public readonly QueryFilter FILTER; #endregion //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ #region --Constructors-- - public QueryArchiveMessage(string from, string to) : base(from, to, SET, getRandomId()) { } + public QueryArchiveMessage(QueryFilter filter) : base(null, null, SET, getRandomId()) + { + QUERY_ID = getRandomId(); + FILTER = filter; + } #endregion //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ @@ -33,7 +39,10 @@ public QueryArchiveMessage(string from, string to) : base(from, to, SET, getRand protected override XElement getQuery() { XNamespace ns = Consts.XML_XEP_0313_NAMESPACE; - return new XElement(ns + "query"); + XElement query = new XElement(ns + "query"); + query.Add(new XAttribute("queryid", QUERY_ID)); + FILTER.addToXElement(query); + return query; } #endregion diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveResultMessage.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveResultMessage.cs new file mode 100644 index 000000000..067d86d58 --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryArchiveResultMessage.cs @@ -0,0 +1,74 @@ +using System.Xml; +using System.Xml.Linq; + +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0313 +{ + public class QueryArchiveResultMessage: IQMessage + { + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + public readonly MessageMessage MESSAGE; + public readonly string QUERY_ID; + public readonly string RESULT_ID; + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + public QueryArchiveResultMessage(XmlNode answer) : base(answer) + { + XmlNode resultNode = XMLUtils.getChildNode(answer, "result", Consts.XML_XMLNS, Consts.XML_XEP_0313_NAMESPACE); + if (!(resultNode is null)) + { + QUERY_ID = resultNode.Attributes["queryid"]?.Value; + XmlNode forwardedNode = XMLUtils.getChildNode(resultNode, "forwarded", Consts.XML_XMLNS, Consts.XML_XEP_0297_NAMESPACE); + if (!(forwardedNode is null)) + { + XmlNode messageNode = XMLUtils.getChildNode(forwardedNode, "message"); + if (!(messageNode is null)) + { + MESSAGE = new MessageMessage(messageNode, CarbonCopyType.NONE); + + XmlNode delayNode = XMLUtils.getChildNode(forwardedNode, "delay", Consts.XML_XMLNS, Consts.XML_XEP_0203_NAMESPACE); + if (!(delayNode is null)) + { + MESSAGE.parseDelay(delayNode); + } + } + } + } + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + + + #endregion + + #region --Misc Methods (Private)-- + + + #endregion + + #region --Misc Methods (Protected)-- + protected override XElement getQuery() + { + XNamespace ns = Consts.XML_XEP_0313_NAMESPACE; + XElement query = new XElement(ns + "query"); + query.Add(new XAttribute("queryid", QUERY_ID)); + return query; + } + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryFilter.cs b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryFilter.cs new file mode 100644 index 000000000..8a9f51067 --- /dev/null +++ b/XMPP_API/Classes/Network/XML/Messages/XEP-0313/QueryFilter.cs @@ -0,0 +1,65 @@ +using System.Xml.Linq; +using XMPP_API.Classes.Network.XML.Messages.XEP_0004; + +namespace XMPP_API.Classes.Network.XML.Messages.XEP_0313 +{ + public class QueryFilter + { + //--------------------------------------------------------Attributes:-----------------------------------------------------------------\\ + #region --Attributes-- + private DataForm form = new DataForm(DataFormType.SUBMIT); + + #endregion + //--------------------------------------------------------Constructor:----------------------------------------------------------------\\ + #region --Constructors-- + public QueryFilter() + { + form.fields.Add(new Field() + { + var = "FORM_TYPE", + type = FieldType.HIDDEN, + value = Consts.XML_XEP_0313_NAMESPACE + }); + } + + #endregion + //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\ + #region --Set-, Get- Methods-- + + + #endregion + //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\ + #region --Misc Methods (Public)-- + public void addToXElement(XElement node) + { + form.addToXElement(node); + } + + public void with(string jid) + { + form.fields.Add(new Field() + { + var = "with", + type = FieldType.NONE, + value = jid + }); + } + + #endregion + + #region --Misc Methods (Private)-- + + + #endregion + + #region --Misc Methods (Protected)-- + + + #endregion + //--------------------------------------------------------Events:---------------------------------------------------------------------\\ + #region --Events-- + + + #endregion + } +} diff --git a/XMPP_API/Classes/Network/XML/XMLUtils.cs b/XMPP_API/Classes/Network/XML/XMLUtils.cs index 40475a376..6b3c2260b 100644 --- a/XMPP_API/Classes/Network/XML/XMLUtils.cs +++ b/XMPP_API/Classes/Network/XML/XMLUtils.cs @@ -156,7 +156,7 @@ public static XmlAttribute getAttribute(XmlNode node, in string name) /// /// Tries to pars the given string to a boolean. - /// ' 1 '/'1'/' true '/'true'/' True '/'True' result in true. + /// '1', 'true', 'True' result in true. /// Everything else results in false. /// /// The string containing the boolean. diff --git a/XMPP_API/XMPP_API.csproj b/XMPP_API/XMPP_API.csproj index 70fb7cfd0..5a40c4a37 100644 --- a/XMPP_API/XMPP_API.csproj +++ b/XMPP_API/XMPP_API.csproj @@ -267,6 +267,7 @@ + @@ -307,6 +308,10 @@ + + + +