Skip to content
This repository has been archived by the owner on Jan 29, 2024. It is now read-only.

Commit

Permalink
Basic XEP-0313: Message Archive Management support #139
Browse files Browse the repository at this point in the history
  • Loading branch information
COM8 committed Oct 9, 2020
1 parent 2d76bac commit 13ee5d6
Show file tree
Hide file tree
Showing 14 changed files with 484 additions and 21 deletions.
7 changes: 6 additions & 1 deletion UWPX_UI/Controls/Chat/ChatDetailsControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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<MamResult> result = await Chat.Client.GENERAL_COMMAND_HELPER.requestMamAsync(filter);
}
}

Expand Down
5 changes: 5 additions & 0 deletions XMPP_API/Classes/Consts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
}
32 changes: 32 additions & 0 deletions XMPP_API/Classes/GeneralCommandHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Logging;
using XMPP_API.Classes.Network;
Expand All @@ -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
Expand Down Expand Up @@ -241,6 +243,36 @@ public async Task<MessageResponseHelperResult<IQMessage>> disableMessageCarbonsA
return await helper.startAsync(msg);
}

/// <summary>
/// Sends a <seealso cref="QueryArchiveMessage"/> to the server and requests the MAM archive.
/// </summary>
/// <returns>The result of the request.</returns>
public async Task<MessageResponseHelperResult<MamResult>> requestMamAsync(QueryFilter filter)
{
QueryArchiveMessage msg = new QueryArchiveMessage(filter);
List<QueryArchiveResultMessage> results = new List<QueryArchiveResultMessage>();
Predicate<AbstractAddressableMessage> 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<AbstractAddressableMessage> helper = new AsyncMessageResponseHelper<AbstractAddressableMessage>(CONNECTION, predicate)
{
matchId = false
};
MessageResponseHelperResult<AbstractAddressableMessage> finResult = await helper.startAsync(msg);
MamResult mamResult = null;
if (finResult.STATE == MessageResponseHelperResultState.SUCCESS)
{
mamResult = new MamResult(finResult.RESULT as QueryArchiveFinishMessage, results);
}
return new MessageResponseHelperResult<MamResult>(finResult.STATE, mamResult);
}

#endregion

#region --Misc Methods (Private)--
Expand Down
16 changes: 14 additions & 2 deletions XMPP_API/Classes/Network/XML/MessageParser2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -352,9 +353,15 @@ private List<AbstractMessage> 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;
Expand Down Expand Up @@ -488,6 +495,11 @@ private void parseMessageMessage(List<AbstractMessage> 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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace XMPP_API.Classes.Network.XML.Messages.Helper
{
public class MessageResponseHelperResult<T> where T : AbstractAddressableMessage
public class MessageResponseHelperResult<T> where T : class
{
//--------------------------------------------------------Attributes:-----------------------------------------------------------------\\
#region --Attributes--
Expand Down
34 changes: 21 additions & 13 deletions XMPP_API/Classes/Network/XML/Messages/MessageMessage.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Xml;
using System.Xml.Linq;

Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -227,6 +221,20 @@ public void addDelay(DateTime date)
delay = date;
}

/// <summary>
/// Parses a XEP-0203 (Delayed Delivery).
/// </summary>
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)--
Expand Down
120 changes: 120 additions & 0 deletions XMPP_API/Classes/Network/XML/Messages/XEP-0059/Set.cs
Original file line number Diff line number Diff line change
@@ -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
}
}
69 changes: 69 additions & 0 deletions XMPP_API/Classes/Network/XML/Messages/XEP-0313/MamResult.cs
Original file line number Diff line number Diff line change
@@ -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<QueryArchiveResultMessage> RESULTS;

#endregion
//--------------------------------------------------------Constructor:----------------------------------------------------------------\\
#region --Constructors--
public MamResult(QueryArchiveFinishMessage msg, List<QueryArchiveResultMessage> 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
}
}
Loading

0 comments on commit 13ee5d6

Please sign in to comment.