diff --git a/parsers/doap.xml b/parsers/doap.xml
index 11795578..5fa44830 100644
--- a/parsers/doap.xml
+++ b/parsers/doap.xml
@@ -460,7 +460,7 @@
complete
- 1.0.0
+ 1.1.1
0.1.0
diff --git a/parsers/src/mam.rs b/parsers/src/mam.rs
index decddcdc..9946ce91 100644
--- a/parsers/src/mam.rs
+++ b/parsers/src/mam.rs
@@ -4,7 +4,13 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+use xso::{
+ error::{Error, FromElementError},
+ FromXml, IntoXml,
+};
+
use crate::data_forms::DataForm;
+use crate::date::DateTime;
use crate::forwarding::Forwarded;
use crate::iq::{IqGetPayload, IqResultPayload, IqSetPayload};
use crate::message::MessagePayload;
@@ -13,7 +19,6 @@ use crate::pubsub::NodeName;
use crate::rsm::{SetQuery, SetResult};
use crate::Element;
use minidom::Node;
-use xso::error::{Error, FromElementError};
generate_id!(
/// An identifier matching a result message to the query requesting it.
@@ -159,6 +164,52 @@ generate_element!(
impl IqResultPayload for Fin {}
+/// Metadata of the first message in the archive.
+#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::MAM, name = "start")]
+pub struct Start {
+ /// The id of the first message in the archive.
+ #[xml(attribute)]
+ pub id: String,
+
+ /// Time at which that message was sent.
+ #[xml(attribute)]
+ pub timestamp: DateTime,
+}
+
+/// Metadata of the last message in the archive.
+#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::MAM, name = "end")]
+pub struct End {
+ /// The id of the last message in the archive.
+ #[xml(attribute)]
+ pub id: String,
+
+ /// Time at which that message was sent.
+ #[xml(attribute)]
+ pub timestamp: DateTime,
+}
+
+/// Request an archive for its metadata.
+#[derive(FromXml, IntoXml, Debug, Clone, PartialEq)]
+#[xml(namespace = ns::MAM, name = "metadata")]
+pub struct MetadataQuery;
+
+impl IqGetPayload for MetadataQuery {}
+
+generate_element!(
+/// Response from the archive, containing the start and end metadata if it isn’t empty.
+MetadataResponse, "metadata", MAM,
+children: [
+ /// Metadata about the first message in the archive.
+ start: Option = ("start", MAM) => Start,
+
+ /// Metadata about the last message in the archive.
+ end: Option = ("end", MAM) => End,
+]);
+
+impl IqResultPayload for MetadataResponse {}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -171,6 +222,10 @@ mod tests {
assert_size!(Result_, 164);
assert_size!(Complete, 1);
assert_size!(Fin, 44);
+ assert_size!(Start, 28);
+ assert_size!(End, 28);
+ assert_size!(MetadataQuery, 0);
+ assert_size!(MetadataResponse, 56);
}
#[cfg(target_pointer_width = "64")]
@@ -181,6 +236,10 @@ mod tests {
assert_size!(Result_, 312);
assert_size!(Complete, 1);
assert_size!(Fin, 88);
+ assert_size!(Start, 40);
+ assert_size!(End, 40);
+ assert_size!(MetadataQuery, 0);
+ assert_size!(MetadataResponse, 80);
}
#[test]
@@ -291,6 +350,26 @@ mod tests {
Query::try_from(elem).unwrap();
}
+ #[test]
+ fn test_metadata() {
+ let elem: Element = r"".parse().unwrap();
+ MetadataQuery::try_from(elem).unwrap();
+
+ let elem: Element = r"
+
+
+"
+ .parse()
+ .unwrap();
+ let metadata = MetadataResponse::try_from(elem).unwrap();
+ let start = metadata.start.unwrap();
+ let end = metadata.end.unwrap();
+ assert_eq!(start.id, "YWxwaGEg");
+ assert_eq!(start.timestamp.0.timestamp(), 1219439344);
+ assert_eq!(end.id, "b21lZ2Eg");
+ assert_eq!(end.timestamp.0.timestamp(), 1587393261);
+ }
+
#[test]
fn test_invalid_child() {
let elem: Element = ""