diff --git a/packages/moxxmpp/lib/src/connection.dart b/packages/moxxmpp/lib/src/connection.dart
index b752114..6888713 100644
--- a/packages/moxxmpp/lib/src/connection.dart
+++ b/packages/moxxmpp/lib/src/connection.dart
@@ -27,7 +27,9 @@ import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
import 'package:moxxmpp/src/types/result.dart';
import 'package:moxxmpp/src/util/queue.dart';
+import 'package:moxxmpp/src/util/typed_map.dart';
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
+import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
import 'package:moxxmpp/src/xeps/xep_0198/xep_0198.dart';
import 'package:moxxmpp/src/xeps/xep_0352.dart';
import 'package:synchronized/synchronized.dart';
@@ -474,8 +476,8 @@ class XmppConnection {
initial: StanzaHandlerData(
false,
false,
- null,
newStanza,
+ TypedMap(),
encrypted: details.encrypted,
forceEncryption: details.forceEncryption,
),
@@ -531,14 +533,15 @@ class XmppConnection {
// Run post-send handlers
_log.fine('Running post stanza handlers..');
+ final extensions = TypedMap()
+ ..set(StreamManagementData(details.excludeFromStreamManagement));
await _runOutgoingPostStanzaHandlers(
newStanza,
initial: StanzaHandlerData(
false,
false,
- null,
newStanza,
- excludeFromStreamManagement: details.excludeFromStreamManagement,
+ extensions,
),
);
_log.fine('Done');
@@ -653,7 +656,7 @@ class XmppConnection {
Stanza stanza, {
StanzaHandlerData? initial,
}) async {
- var state = initial ?? StanzaHandlerData(false, false, null, stanza);
+ var state = initial ?? StanzaHandlerData(false, false, stanza, TypedMap());
for (final handler in handlers) {
if (handler.matches(state.stanza)) {
state = await handler.callback(state.stanza, state);
@@ -728,7 +731,7 @@ class XmppConnection {
// it.
final incomingPreHandlers = await _runIncomingPreStanzaHandlers(stanza);
final prefix = incomingPreHandlers.encrypted &&
- incomingPreHandlers.other['encryption_error'] == null
+ incomingPreHandlers.encryptionError == null
? '(Encrypted) '
: '';
_log.finest('<== $prefix${incomingPreHandlers.stanza.toXml()}');
@@ -747,10 +750,10 @@ class XmppConnection {
initial: StanzaHandlerData(
false,
incomingPreHandlers.cancel,
- incomingPreHandlers.cancelReason,
incomingPreHandlers.stanza,
+ incomingPreHandlers.extensions,
encrypted: incomingPreHandlers.encrypted,
- other: incomingPreHandlers.other,
+ cancelReason: incomingPreHandlers.cancelReason,
),
);
if (!incomingHandlers.done) {
diff --git a/packages/moxxmpp/lib/src/managers/data.dart b/packages/moxxmpp/lib/src/managers/data.dart
index 5245808..3109fca 100644
--- a/packages/moxxmpp/lib/src/managers/data.dart
+++ b/packages/moxxmpp/lib/src/managers/data.dart
@@ -1,82 +1,45 @@
-import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:moxxmpp/src/stanza.dart';
-import 'package:moxxmpp/src/xeps/xep_0066.dart';
-import 'package:moxxmpp/src/xeps/xep_0085.dart';
-import 'package:moxxmpp/src/xeps/xep_0203.dart';
-import 'package:moxxmpp/src/xeps/xep_0359.dart';
-import 'package:moxxmpp/src/xeps/xep_0380.dart';
-import 'package:moxxmpp/src/xeps/xep_0385.dart';
-import 'package:moxxmpp/src/xeps/xep_0424.dart';
-import 'package:moxxmpp/src/xeps/xep_0444.dart';
-import 'package:moxxmpp/src/xeps/xep_0446.dart';
-import 'package:moxxmpp/src/xeps/xep_0447.dart';
-import 'package:moxxmpp/src/xeps/xep_0461.dart';
+import 'package:moxxmpp/src/util/typed_map.dart';
-part 'data.freezed.dart';
+class StanzaHandlerData {
+ StanzaHandlerData(
+ this.done,
+ this.cancel,
+ this.stanza,
+ this.extensions, {
+ this.cancelReason,
+ this.encryptionError,
+ this.encrypted = false,
+ this.forceEncryption = false,
+ });
-@freezed
-class StanzaHandlerData with _$StanzaHandlerData {
- factory StanzaHandlerData(
- // Indicates to the runner that processing is now done. This means that all
- // pre-processing is done and no other handlers should be consulted.
- bool done,
- // Indicates to the runner that processing is to be cancelled and no further handlers
- // should run. The stanza also will not be sent.
- bool cancel,
- // The reason why we cancelled the processing and sending
- dynamic cancelReason,
- // The stanza that is being dealt with. SHOULD NOT be overwritten, unless it is absolutely
- // necessary, e.g. with Message Carbons or OMEMO
- Stanza stanza, {
- // Whether the stanza is retransmitted. Only useful in the context of outgoing
- // stanza handlers. MUST NOT be overwritten.
- @Default(false) bool retransmitted,
- StatelessMediaSharingData? sims,
- StatelessFileSharingData? sfs,
- OOBData? oob,
+ /// Indicates to the runner that processing is now done. This means that all
+ /// pre-processing is done and no other handlers should be consulted.
+ bool done;
- // XEP-0359 's id attribute, if available.
- String? originId,
+ /// Indicates to the runner that processing is to be cancelled and no further handlers
+ /// should run. The stanza also will not be sent.
+ bool cancel;
- // XEP-0359 elements, if available.
- List? stanzaIds,
- ReplyData? reply,
- ChatState? chatState,
- @Default(false) bool isCarbon,
- @Default(false) bool deliveryReceiptRequested,
- @Default(false) bool isMarkable,
- // File Upload Notifications
- // A notification
- FileMetadataData? fun,
- // The stanza id this replaces
- String? funReplacement,
- // The stanza id this cancels
- String? funCancellation,
- // Whether the stanza was received encrypted
- @Default(false) bool encrypted,
- // If true, forces the encryption manager to encrypt to the JID, even if it
- // would not normally. In the case of OMEMO: If shouldEncrypt returns false
- // but forceEncryption is true, then the OMEMO manager will try to encrypt
- // to the JID anyway.
- @Default(false) bool forceEncryption,
- // The stated type of encryption used, if any was used
- ExplicitEncryptionType? encryptionType,
- // Delayed Delivery
- DelayedDelivery? delayedDelivery,
- // This is for stanza handlers that are not part of the XMPP library but still need
- // pass data around.
- @Default({}) Map other,
- // If non-null, then it indicates the origin Id of the message that should be
- // retracted
- MessageRetractionData? messageRetraction,
- // If non-null, then the message is a correction for the specified stanza Id
- String? lastMessageCorrectionSid,
- // Reactions data
- MessageReactions? messageReactions,
- // The Id of the sticker pack this sticker belongs to
- String? stickerPackId,
- // Flag indicating whether the stanza should be excluded from stream management's
- // resending behaviour
- @Default(false) bool excludeFromStreamManagement,
- }) = _StanzaHandlerData;
+ /// The reason why we cancelled the processing and sending.
+ Object? cancelReason;
+
+ /// The reason why an encryption or decryption failed.
+ Object? encryptionError;
+
+ /// The stanza that is being dealt with. SHOULD NOT be overwritten, unless it is
+ /// absolutely necessary, e.g. with Message Carbons or OMEMO.
+ Stanza stanza;
+
+ /// Whether the stanza was received encrypted
+ bool encrypted;
+
+ // If true, forces the encryption manager to encrypt to the JID, even if it
+ // would not normally. In the case of OMEMO: If shouldEncrypt returns false
+ // but forceEncryption is true, then the OMEMO manager will try to encrypt
+ // to the JID anyway.
+ bool forceEncryption;
+
+ /// Additional data from other managers.
+ final TypedMap extensions;
}
diff --git a/packages/moxxmpp/lib/src/message.dart b/packages/moxxmpp/lib/src/message.dart
index ae3ea31..92d0eed 100644
--- a/packages/moxxmpp/lib/src/message.dart
+++ b/packages/moxxmpp/lib/src/message.dart
@@ -12,15 +12,18 @@ import 'package:moxxmpp/src/xeps/staging/file_upload_notification.dart';
import 'package:moxxmpp/src/xeps/xep_0066.dart';
import 'package:moxxmpp/src/xeps/xep_0085.dart';
import 'package:moxxmpp/src/xeps/xep_0184.dart';
+import 'package:moxxmpp/src/xeps/xep_0280.dart';
import 'package:moxxmpp/src/xeps/xep_0308.dart';
import 'package:moxxmpp/src/xeps/xep_0333.dart';
import 'package:moxxmpp/src/xeps/xep_0334.dart';
import 'package:moxxmpp/src/xeps/xep_0359.dart';
+import 'package:moxxmpp/src/xeps/xep_0385.dart';
import 'package:moxxmpp/src/xeps/xep_0424.dart';
import 'package:moxxmpp/src/xeps/xep_0444.dart';
import 'package:moxxmpp/src/xeps/xep_0446.dart';
import 'package:moxxmpp/src/xeps/xep_0447.dart';
import 'package:moxxmpp/src/xeps/xep_0448.dart';
+import 'package:moxxmpp/src/xeps/xep_0449.dart';
import 'package:moxxmpp/src/xeps/xep_0461.dart';
/// Data used to build a message stanza.
@@ -100,7 +103,7 @@ class MessageManager extends XmppManagerBase {
final hints = List.empty(growable: true);
for (final element
in message.findTagsByXmlns(messageProcessingHintsXmlns)) {
- hints.add(messageProcessingHintFromXml(element));
+ hints.add(MessageProcessingHint.fromName(element.tag));
}
getAttributes().sendEvent(
@@ -109,32 +112,37 @@ class MessageManager extends XmppManagerBase {
fromJid: JID.fromString(message.attributes['from']! as String),
toJid: JID.fromString(message.attributes['to']! as String),
sid: message.attributes['id']! as String,
- originId: state.originId,
- stanzaIds: state.stanzaIds,
- isCarbon: state.isCarbon,
- deliveryReceiptRequested: state.deliveryReceiptRequested,
- isMarkable: state.isMarkable,
+ originId: state.extensions.get()?.originId,
+ stanzaIds: state.extensions.get()?.stanzaIds,
+ isCarbon: state.extensions.get()?.isCarbon ?? false,
+ deliveryReceiptRequested: state.extensions
+ .get()
+ ?.receiptRequested ??
+ false,
+ isMarkable: state.extensions.get()?.isMarkable ?? false,
type: message.attributes['type'] as String?,
- oob: state.oob,
- sfs: state.sfs,
- sims: state.sims,
- reply: state.reply,
- chatState: state.chatState,
- fun: state.fun,
- funReplacement: state.funReplacement,
- funCancellation: state.funCancellation,
+ oob: state.extensions.get(),
+ sfs: state.extensions.get(),
+ sims: state.extensions.get(),
+ reply: state.extensions.get(),
+ chatState: state.extensions.get(),
+ fun: state.extensions.get()?.metadata,
+ funReplacement:
+ state.extensions.get()?.id,
+ funCancellation:
+ state.extensions.get()?.id,
encrypted: state.encrypted,
- messageRetraction: state.messageRetraction,
- messageCorrectionId: state.lastMessageCorrectionSid,
- messageReactions: state.messageReactions,
+ messageRetraction: state.extensions.get(),
+ messageCorrectionId: state.extensions.get()?.id,
+ messageReactions: state.extensions.get(),
messageProcessingHints: hints.isEmpty ? null : hints,
- stickerPackId: state.stickerPackId,
- other: state.other,
+ stickerPackId: state.extensions.get()?.stickerPackId,
+ other: {},
error: StanzaError.fromStanza(message),
),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
/// Send a message to to with the content body. If deliveryRequest is true, then
@@ -142,7 +150,7 @@ class MessageManager extends XmppManagerBase {
/// If id is non-null, then it will be the id of the message stanza.
/// element to this id. If originId is non-null, then it will create an "origin-id"
/// child in the message stanza and set its id to originId.
- void sendMessage(MessageDetails details) {
+ Future sendMessage(MessageDetails details) async {
assert(
implies(
details.quoteBody != null,
@@ -216,7 +224,7 @@ class MessageManager extends XmppManagerBase {
stanza.addChild(makeChatMarkerMarkable());
}
if (details.originId != null) {
- stanza.addChild(makeOriginIdElement(details.originId!));
+ stanza.addChild(StableIdData(details.originId, null).toOriginIdElement());
}
if (details.sfs != null) {
@@ -226,17 +234,13 @@ class MessageManager extends XmppManagerBase {
if (source is StatelessFileSharingUrlSource &&
details.setOOBFallbackBody) {
// SFS recommends OOB as a fallback
- stanza.addChild(constructOOBNode(OOBData(url: source.url)));
+ stanza.addChild(OOBData(source.url, null).toXML());
}
}
if (details.chatState != null) {
stanza.addChild(
- // TODO(Unknown): Move this into xep_0085.dart
- XMLNode.xmlns(
- tag: chatStateToString(details.chatState!),
- xmlns: chatStateXmlns,
- ),
+ details.chatState!.toXML(),
);
}
@@ -293,9 +297,9 @@ class MessageManager extends XmppManagerBase {
if (details.lastMessageCorrectionId != null) {
stanza.addChild(
- makeLastMessageCorrectionEdit(
+ LastMessageCorrectionData(
details.lastMessageCorrectionId!,
- ),
+ ).toXML(),
);
}
@@ -305,7 +309,7 @@ class MessageManager extends XmppManagerBase {
if (details.messageProcessingHints != null) {
for (final hint in details.messageProcessingHints!) {
- stanza.addChild(hint.toXml());
+ stanza.addChild(hint.toXML());
}
}
@@ -321,7 +325,7 @@ class MessageManager extends XmppManagerBase {
);
}
- getAttributes().sendStanza(
+ await getAttributes().sendStanza(
StanzaDetails(
stanza,
awaitable: false,
diff --git a/packages/moxxmpp/lib/src/presence.dart b/packages/moxxmpp/lib/src/presence.dart
index c9931ad..41e1013 100644
--- a/packages/moxxmpp/lib/src/presence.dart
+++ b/packages/moxxmpp/lib/src/presence.dart
@@ -66,7 +66,7 @@ class PresenceManager extends XmppManagerBase {
from: JID.fromString(presence.from!),
),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
default:
break;
@@ -78,7 +78,7 @@ class PresenceManager extends XmppManagerBase {
getAttributes().sendEvent(
PresenceReceivedEvent(JID.fromString(presence.from!), presence),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
return state;
diff --git a/packages/moxxmpp/lib/src/roster/roster.dart b/packages/moxxmpp/lib/src/roster/roster.dart
index 6c08d34..c6d7758 100644
--- a/packages/moxxmpp/lib/src/roster/roster.dart
+++ b/packages/moxxmpp/lib/src/roster/roster.dart
@@ -145,7 +145,7 @@ class RosterManager extends XmppManagerBase {
logger.warning(
'Roster push invalid! Unexpected from attribute: ${stanza.toXml()}',
);
- return state.copyWith(done: true);
+ return state..done = true;
}
final query = stanza.firstTag('query', xmlns: rosterXmlns)!;
@@ -154,7 +154,7 @@ class RosterManager extends XmppManagerBase {
if (item == null) {
logger.warning('Received empty roster push');
- return state.copyWith(done: true);
+ return state..done = true;
}
unawaited(
@@ -177,7 +177,7 @@ class RosterManager extends XmppManagerBase {
[],
);
- return state.copyWith(done: true);
+ return state..done = true;
}
/// Shared code between requesting rosters without and with roster versioning, if
diff --git a/packages/moxxmpp/lib/src/xeps/staging/file_upload_notification.dart b/packages/moxxmpp/lib/src/xeps/staging/file_upload_notification.dart
index 7c1caad..51d60ff 100644
--- a/packages/moxxmpp/lib/src/xeps/staging/file_upload_notification.dart
+++ b/packages/moxxmpp/lib/src/xeps/staging/file_upload_notification.dart
@@ -7,9 +7,32 @@ import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/xeps/xep_0446.dart';
/// NOTE: Specified by https://github.com/PapaTutuWawa/custom-xeps/blob/master/xep-xxxx-file-upload-notifications.md
-
const fileUploadNotificationXmlns = 'proto:urn:xmpp:fun:0';
+/// Indicates a file upload notification.
+class FileUploadNotificationData {
+ const FileUploadNotificationData(this.metadata);
+
+ /// The file metadata indicated in the upload notification.
+ final FileMetadataData metadata;
+}
+
+/// Indicates that a file upload has been cancelled.
+class FileUploadNotificationCancellationData {
+ const FileUploadNotificationCancellationData(this.id);
+
+ /// The id of the upload notifiaction that is cancelled.
+ final String id;
+}
+
+/// Indicates that a file upload has been completed.
+class FileUploadNotificationReplacementData {
+ const FileUploadNotificationReplacementData(this.id);
+
+ /// The id of the upload notifiaction that is replaced.
+ final String id;
+}
+
class FileUploadNotificationManager extends XmppManagerBase {
FileUploadNotificationManager() : super(fileUploadNotificationManager);
@@ -47,11 +70,14 @@ class FileUploadNotificationManager extends XmppManagerBase {
) async {
final funElement =
message.firstTag('file-upload', xmlns: fileUploadNotificationXmlns)!;
- return state.copyWith(
- fun: FileMetadataData.fromXML(
- funElement.firstTag('file', xmlns: fileMetadataXmlns)!,
- ),
- );
+ return state
+ ..extensions.set(
+ FileUploadNotificationData(
+ FileMetadataData.fromXML(
+ funElement.firstTag('file', xmlns: fileMetadataXmlns)!,
+ ),
+ ),
+ );
}
Future _onFileUploadNotificationReplacementReceived(
@@ -60,9 +86,12 @@ class FileUploadNotificationManager extends XmppManagerBase {
) async {
final element =
message.firstTag('replaces', xmlns: fileUploadNotificationXmlns)!;
- return state.copyWith(
- funReplacement: element.attributes['id']! as String,
- );
+ return state
+ ..extensions.set(
+ FileUploadNotificationReplacementData(
+ element.attributes['id']! as String,
+ ),
+ );
}
Future _onFileUploadNotificationCancellationReceived(
@@ -71,8 +100,11 @@ class FileUploadNotificationManager extends XmppManagerBase {
) async {
final element =
message.firstTag('cancels', xmlns: fileUploadNotificationXmlns)!;
- return state.copyWith(
- funCancellation: element.attributes['id']! as String,
- );
+ return state
+ ..extensions.set(
+ FileUploadNotificationCancellationData(
+ element.attributes['id']! as String,
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart b/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart
index 263cdce..903304e 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0030/xep_0030.dart
@@ -184,7 +184,7 @@ class DiscoManager extends XmppManagerBase {
],
);
- return state.copyWith(done: true);
+ return state..done = true;
}
await reply(
@@ -195,7 +195,7 @@ class DiscoManager extends XmppManagerBase {
],
);
- return state.copyWith(done: true);
+ return state..done = true;
}
Future _onDiscoItemsRequest(
@@ -223,7 +223,7 @@ class DiscoManager extends XmppManagerBase {
],
);
- return state.copyWith(done: true);
+ return state..done = true;
}
return state;
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0054.dart b/packages/moxxmpp/lib/src/xeps/xep_0054.dart
index 48031ed..19d0717 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0054.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0054.dart
@@ -76,7 +76,7 @@ class VCardManager extends XmppManagerBase {
}
}
- return state.copyWith(done: true);
+ return state..done = true;
}
VCardPhoto? _parseVCardPhoto(XMLNode? node) {
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0060/xep_0060.dart b/packages/moxxmpp/lib/src/xeps/xep_0060/xep_0060.dart
index 99f7a49..c840c37 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0060/xep_0060.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0060/xep_0060.dart
@@ -114,7 +114,7 @@ class PubSubManager extends XmppManagerBase {
),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
Future _getNodeItemCount(JID jid, String node) async {
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0066.dart b/packages/moxxmpp/lib/src/xeps/xep_0066.dart
index 61bb4cc..a008be3 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0066.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0066.dart
@@ -8,26 +8,24 @@ import 'package:moxxmpp/src/stringxml.dart';
/// A data class representing the jabber:x:oob tag.
class OOBData {
- const OOBData({this.url, this.desc});
+ const OOBData(this.url, this.desc);
+
+ /// The communicated URL of the OOB data
final String? url;
+
+ /// The description of the url.
final String? desc;
-}
-XMLNode constructOOBNode(OOBData data) {
- final children = List.empty(growable: true);
-
- if (data.url != null) {
- children.add(XMLNode(tag: 'url', text: data.url));
+ XMLNode toXML() {
+ return XMLNode.xmlns(
+ tag: 'x',
+ xmlns: oobDataXmlns,
+ children: [
+ if (url != null) XMLNode(tag: 'url', text: url),
+ if (desc != null) XMLNode(tag: 'desc', text: desc),
+ ],
+ );
}
- if (data.desc != null) {
- children.add(XMLNode(tag: 'desc', text: data.desc));
- }
-
- return XMLNode.xmlns(
- tag: 'x',
- xmlns: oobDataXmlns,
- children: children,
- );
}
class OOBManager extends XmppManagerBase {
@@ -59,11 +57,12 @@ class OOBManager extends XmppManagerBase {
final url = x.firstTag('url');
final desc = x.firstTag('desc');
- return state.copyWith(
- oob: OOBData(
- url: url?.innerText(),
- desc: desc?.innerText(),
- ),
- );
+ return state
+ ..extensions.set(
+ OOBData(
+ url?.innerText(),
+ desc?.innerText(),
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0085.dart b/packages/moxxmpp/lib/src/xeps/xep_0085.dart
index ab28ab1..f0d25f7 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0085.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0085.dart
@@ -6,39 +6,54 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
-enum ChatState { active, composing, paused, inactive, gone }
+enum ChatState {
+ active,
+ composing,
+ paused,
+ inactive,
+ gone;
-ChatState chatStateFromString(String raw) {
- switch (raw) {
- case 'active':
- {
+ factory ChatState.fromString(String state) {
+ switch (state) {
+ case 'active':
return ChatState.active;
- }
- case 'composing':
- {
+ case 'composing':
return ChatState.composing;
- }
- case 'paused':
- {
+ case 'paused':
return ChatState.paused;
- }
- case 'inactive':
- {
+ case 'inactive':
return ChatState.inactive;
- }
- case 'gone':
- {
+ case 'gone':
return ChatState.gone;
- }
- default:
- {
+ default:
return ChatState.gone;
- }
+ }
+ }
+
+ @override
+ String toString() {
+ switch (this) {
+ case ChatState.active:
+ return 'active';
+ case ChatState.composing:
+ return 'composing';
+ case ChatState.paused:
+ return 'paused';
+ case ChatState.inactive:
+ return 'inactive';
+ case ChatState.gone:
+ return 'gone';
+ }
+ }
+
+ XMLNode toXML() {
+ return XMLNode.xmlns(
+ tag: toString(),
+ xmlns: chatStateXmlns,
+ );
}
}
-String chatStateToString(ChatState state) => state.toString().split('.').last;
-
class ChatStateManager extends XmppManagerBase {
ChatStateManager() : super(chatStateManager);
@@ -64,61 +79,27 @@ class ChatStateManager extends XmppManagerBase {
StanzaHandlerData state,
) async {
final element = state.stanza.firstTagByXmlns(chatStateXmlns)!;
- ChatState? chatState;
-
- switch (element.tag) {
- case 'active':
- {
- chatState = ChatState.active;
- }
- break;
- case 'composing':
- {
- chatState = ChatState.composing;
- }
- break;
- case 'paused':
- {
- chatState = ChatState.paused;
- }
- break;
- case 'inactive':
- {
- chatState = ChatState.inactive;
- }
- break;
- case 'gone':
- {
- chatState = ChatState.gone;
- }
- break;
- default:
- {
- logger.warning("Received invalid chat state '${element.tag}'");
- }
- }
-
- return state.copyWith(chatState: chatState);
+ state.extensions.set(ChatState.fromString(element.tag));
+ return state;
}
/// Send a chat state notification to [to]. You can specify the type attribute
/// of the message with [messageType].
- void sendChatState(
+ Future sendChatState(
ChatState state,
String to, {
String messageType = 'chat',
- }) {
- final tagName = state.toString().split('.').last;
-
- getAttributes().sendStanza(
+ }) async {
+ await getAttributes().sendStanza(
StanzaDetails(
Stanza.message(
to: to,
type: messageType,
children: [
- XMLNode.xmlns(tag: tagName, xmlns: chatStateXmlns),
+ XMLNode.xmlns(tag: state.toString(), xmlns: chatStateXmlns),
],
),
+ awaitable: false,
),
);
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0184.dart b/packages/moxxmpp/lib/src/xeps/xep_0184.dart
index 5a562d2..c0d5e46 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0184.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0184.dart
@@ -8,6 +8,14 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
+class MessageDeliveryReceiptData {
+ const MessageDeliveryReceiptData(this.receiptRequested);
+
+ /// Indicates whether a delivery receipt is requested or not.
+ final bool receiptRequested;
+}
+
+// TODO: Merge those two functions into [MessageDeliveryReceiptData]
XMLNode makeMessageDeliveryRequest() {
return XMLNode.xmlns(
tag: 'request',
@@ -56,7 +64,7 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
Stanza message,
StanzaHandlerData state,
) async {
- return state.copyWith(deliveryReceiptRequested: true);
+ return state..extensions.set(const MessageDeliveryReceiptData(true));
}
Future _onDeliveryReceiptReceived(
@@ -64,16 +72,16 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
StanzaHandlerData state,
) async {
final received = message.firstTag('received', xmlns: deliveryXmlns)!;
- for (final item in message.children) {
- if (!['origin-id', 'stanza-id', 'delay', 'store', 'received']
- .contains(item.tag)) {
- logger.info(
- "Won't handle stanza as delivery receipt because we found an '${item.tag}' element",
- );
+ // for (final item in message.children) {
+ // if (!['origin-id', 'stanza-id', 'delay', 'store', 'received']
+ // .contains(item.tag)) {
+ // logger.info(
+ // "Won't handle stanza as delivery receipt because we found an '${item.tag}' element",
+ // );
- return state.copyWith(done: true);
- }
- }
+ // return state.copyWith(done: true);
+ // }
+ // }
getAttributes().sendEvent(
DeliveryReceiptReceivedEvent(
@@ -81,6 +89,6 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
id: received.attributes['id']! as String,
),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0191.dart b/packages/moxxmpp/lib/src/xeps/xep_0191.dart
index c443d0d..dcb3395 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0191.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0191.dart
@@ -70,7 +70,7 @@ class BlockingManager extends XmppManagerBase {
),
);
- return state.copyWith(done: true);
+ return state..done = true;
}
Future _unblockPush(
@@ -92,7 +92,7 @@ class BlockingManager extends XmppManagerBase {
);
}
- return state.copyWith(done: true);
+ return state..done = true;
}
Future block(List items) async {
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0198/types.dart b/packages/moxxmpp/lib/src/xeps/xep_0198/types.dart
new file mode 100644
index 0000000..9e26e4c
--- /dev/null
+++ b/packages/moxxmpp/lib/src/xeps/xep_0198/types.dart
@@ -0,0 +1,6 @@
+class StreamManagementData {
+ const StreamManagementData(this.exclude);
+
+ /// Whether the stanza should be exluded from the StreamManagement's resend queue.
+ final bool exclude;
+}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart b/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart
index 9f35880..9ed647f 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0198/xep_0198.dart
@@ -15,6 +15,7 @@ import 'package:moxxmpp/src/xeps/xep_0198/errors.dart';
import 'package:moxxmpp/src/xeps/xep_0198/negotiator.dart';
import 'package:moxxmpp/src/xeps/xep_0198/nonzas.dart';
import 'package:moxxmpp/src/xeps/xep_0198/state.dart';
+import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
import 'package:synchronized/synchronized.dart';
const xmlUintMax = 4294967296; // 2**32
@@ -402,7 +403,9 @@ class StreamManagementManager extends XmppManagerBase {
if (isStreamManagementEnabled()) {
await _incrementC2S();
- if (state.excludeFromStreamManagement) return state;
+ if (state.extensions.get()?.exclude ?? false) {
+ return state;
+ }
_unackedStanzas[_state.c2s] = stanza;
await _sendAckRequest();
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0203.dart b/packages/moxxmpp/lib/src/xeps/xep_0203.dart
index cc33598..a0e7cad 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0203.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0203.dart
@@ -1,4 +1,5 @@
import 'package:meta/meta.dart';
+import 'package:moxxmpp/src/jid.dart';
import 'package:moxxmpp/src/managers/base.dart';
import 'package:moxxmpp/src/managers/data.dart';
import 'package:moxxmpp/src/managers/handlers.dart';
@@ -7,10 +8,14 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
@immutable
-class DelayedDelivery {
- const DelayedDelivery(this.from, this.timestamp);
+class DelayedDeliveryData {
+ const DelayedDeliveryData(this.from, this.timestamp);
+
+ /// The timestamp the message was originally sent.
final DateTime timestamp;
- final String from;
+
+ /// The JID that originally sent the message.
+ final JID from;
}
class DelayedDeliveryManager extends XmppManagerBase {
@@ -23,6 +28,8 @@ class DelayedDeliveryManager extends XmppManagerBase {
List getIncomingStanzaHandlers() => [
StanzaHandler(
stanzaTag: 'message',
+ tagName: 'delay',
+ tagXmlns: delayedDeliveryXmlns,
callback: _onIncomingMessage,
priority: 200,
),
@@ -32,14 +39,14 @@ class DelayedDeliveryManager extends XmppManagerBase {
Stanza stanza,
StanzaHandlerData state,
) async {
- final delay = stanza.firstTag('delay', xmlns: delayedDeliveryXmlns);
- if (delay == null) return state;
+ final delay = stanza.firstTag('delay', xmlns: delayedDeliveryXmlns)!;
- return state.copyWith(
- delayedDelivery: DelayedDelivery(
- delay.attributes['from']! as String,
- DateTime.parse(delay.attributes['stamp']! as String),
- ),
- );
+ return state
+ ..extensions.set(
+ DelayedDeliveryData(
+ JID.fromString(delay.attributes['from']! as String),
+ DateTime.parse(delay.attributes['stamp']! as String),
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0280.dart b/packages/moxxmpp/lib/src/xeps/xep_0280.dart
index d24e8ca..e84f596 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0280.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0280.dart
@@ -14,6 +14,13 @@ import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
import 'package:moxxmpp/src/xeps/xep_0297.dart';
import 'package:moxxmpp/src/xeps/xep_0386.dart';
+class CarbonsData {
+ const CarbonsData(this.isCarbon);
+
+ /// Indicates whether this message is a carbon.
+ final bool isCarbon;
+}
+
/// This manager class implements support for XEP-0280.
class CarbonsManager extends XmppManagerBase {
CarbonsManager() : super(carbonsManager);
@@ -77,15 +84,14 @@ class CarbonsManager extends XmppManagerBase {
) async {
final from = JID.fromString(message.attributes['from']! as String);
final received = message.firstTag('received', xmlns: carbonsXmlns)!;
- if (!isCarbonValid(from)) return state.copyWith(done: true);
+ if (!isCarbonValid(from)) return state..done = true;
final forwarded = received.firstTag('forwarded', xmlns: forwardedXmlns)!;
final carbon = unpackForwarded(forwarded);
- return state.copyWith(
- isCarbon: true,
- stanza: carbon,
- );
+ return state
+ ..extensions.set(const CarbonsData(true))
+ ..stanza = carbon;
}
Future _onMessageSent(
@@ -94,15 +100,14 @@ class CarbonsManager extends XmppManagerBase {
) async {
final from = JID.fromString(message.attributes['from']! as String);
final sent = message.firstTag('sent', xmlns: carbonsXmlns)!;
- if (!isCarbonValid(from)) return state.copyWith(done: true);
+ if (!isCarbonValid(from)) return state..done = true;
final forwarded = sent.firstTag('forwarded', xmlns: forwardedXmlns)!;
final carbon = unpackForwarded(forwarded);
- return state.copyWith(
- isCarbon: true,
- stanza: carbon,
- );
+ return state
+ ..extensions.set(const CarbonsData(true))
+ ..stanza = carbon;
}
/// Send a request to the server, asking it to enable Message Carbons.
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0308.dart b/packages/moxxmpp/lib/src/xeps/xep_0308.dart
index 2cd9aa7..1cc57b8 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0308.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0308.dart
@@ -6,14 +6,21 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
-XMLNode makeLastMessageCorrectionEdit(String id) {
- return XMLNode.xmlns(
- tag: 'replace',
- xmlns: lmcXmlns,
- attributes: {
- 'id': id,
- },
- );
+class LastMessageCorrectionData {
+ const LastMessageCorrectionData(this.id);
+
+ /// The id the LMC applies to.
+ final String id;
+
+ XMLNode toXML() {
+ return XMLNode.xmlns(
+ tag: 'replace',
+ xmlns: lmcXmlns,
+ attributes: {
+ 'id': id,
+ },
+ );
+ }
}
class LastMessageCorrectionManager extends XmppManagerBase {
@@ -42,8 +49,9 @@ class LastMessageCorrectionManager extends XmppManagerBase {
StanzaHandlerData state,
) async {
final edit = stanza.firstTag('replace', xmlns: lmcXmlns)!;
- return state.copyWith(
- lastMessageCorrectionSid: edit.attributes['id']! as String,
- );
+ return state
+ ..extensions.set(
+ LastMessageCorrectionData(edit.attributes['id']! as String),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0333.dart b/packages/moxxmpp/lib/src/xeps/xep_0333.dart
index 76ae8e3..5858d20 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0333.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0333.dart
@@ -8,6 +8,13 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
+class ChatMarkerData {
+ const ChatMarkerData(this.isMarkable);
+
+ /// Indicates whether the message can be replied to with a chat marker.
+ final bool isMarkable;
+}
+
XMLNode makeChatMarkerMarkable() {
return XMLNode.xmlns(
tag: 'markable',
@@ -54,7 +61,9 @@ class ChatMarkerManager extends XmppManagerBase {
final marker = message.firstTagByXmlns(chatMarkersXmlns)!;
// Handle the explicitly
- if (marker.tag == 'markable') return state.copyWith(isMarkable: true);
+ if (marker.tag == 'markable') {
+ return state..extensions.set(const ChatMarkerData(true));
+ }
if (!['received', 'displayed', 'acknowledged'].contains(marker.tag)) {
logger.warning("Unknown message marker '${marker.tag}' found.");
@@ -68,6 +77,6 @@ class ChatMarkerManager extends XmppManagerBase {
);
}
- return state.copyWith(done: true);
+ return state..done = true;
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0334.dart b/packages/moxxmpp/lib/src/xeps/xep_0334.dart
index 57b768e..e4bf1b0 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0334.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0334.dart
@@ -5,27 +5,25 @@ enum MessageProcessingHint {
noPermanentStore,
noStore,
noCopies,
- store,
-}
+ store;
-MessageProcessingHint messageProcessingHintFromXml(XMLNode element) {
- switch (element.tag) {
- case 'no-permanent-store':
- return MessageProcessingHint.noPermanentStore;
- case 'no-store':
- return MessageProcessingHint.noStore;
- case 'no-copy':
- return MessageProcessingHint.noCopies;
- case 'store':
- return MessageProcessingHint.store;
+ factory MessageProcessingHint.fromName(String name) {
+ switch (name) {
+ case 'no-permanent-store':
+ return MessageProcessingHint.noPermanentStore;
+ case 'no-store':
+ return MessageProcessingHint.noStore;
+ case 'no-copy':
+ return MessageProcessingHint.noCopies;
+ case 'store':
+ return MessageProcessingHint.store;
+ }
+
+ assert(false, 'Invalid Message Processing Hint: $name');
+ return MessageProcessingHint.noStore;
}
- assert(false, 'Invalid Message Processing Hint: ${element.tag}');
- return MessageProcessingHint.noStore;
-}
-
-extension XmlExtension on MessageProcessingHint {
- XMLNode toXml() {
+ XMLNode toXML() {
String tag;
switch (this) {
case MessageProcessingHint.noPermanentStore:
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0359.dart b/packages/moxxmpp/lib/src/xeps/xep_0359.dart
index 649edbe..a1cdfb9 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0359.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0359.dart
@@ -7,6 +7,28 @@ import 'package:moxxmpp/src/namespaces.dart';
import 'package:moxxmpp/src/stanza.dart';
import 'package:moxxmpp/src/stringxml.dart';
+class StableIdData {
+ const StableIdData(this.originId, this.stanzaIds);
+
+ ///
+ final String? originId;
+
+ /// Stanza ids
+ final List? stanzaIds;
+
+ XMLNode toOriginIdElement() {
+ assert(
+ originId != null,
+ 'Can only build the XML element if originId != null',
+ );
+ return XMLNode.xmlns(
+ tag: 'origin-id',
+ xmlns: stableIdXmlns,
+ attributes: {'id': originId!},
+ );
+ }
+}
+
/// Representation of a element.
class StanzaId {
const StanzaId(
@@ -32,14 +54,6 @@ class StanzaId {
}
}
-XMLNode makeOriginIdElement(String id) {
- return XMLNode.xmlns(
- tag: 'origin-id',
- xmlns: stableIdXmlns,
- attributes: {'id': id},
- );
-}
-
class StableIdManager extends XmppManagerBase {
StableIdManager() : super(stableIdManager);
@@ -86,9 +100,12 @@ class StableIdManager extends XmppManagerBase {
.toList();
}
- return state.copyWith(
- originId: originId,
- stanzaIds: stanzaIds,
- );
+ return state
+ ..extensions.set(
+ StableIdData(
+ originId,
+ stanzaIds,
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0380.dart b/packages/moxxmpp/lib/src/xeps/xep_0380.dart
index 9022596..f576bbe 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0380.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0380.dart
@@ -13,57 +13,57 @@ enum ExplicitEncryptionType {
omemo,
omemo1,
omemo2,
- unknown,
-}
+ unknown;
-String _explicitEncryptionTypeToString(ExplicitEncryptionType type) {
- switch (type) {
- case ExplicitEncryptionType.otr:
- return emeOtr;
- case ExplicitEncryptionType.legacyOpenPGP:
- return emeLegacyOpenPGP;
- case ExplicitEncryptionType.openPGP:
- return emeOpenPGP;
- case ExplicitEncryptionType.omemo:
- return emeOmemo;
- case ExplicitEncryptionType.omemo1:
- return emeOmemo1;
- case ExplicitEncryptionType.omemo2:
- return emeOmemo2;
- case ExplicitEncryptionType.unknown:
- return '';
+ factory ExplicitEncryptionType.fromNamespace(String namespace) {
+ switch (namespace) {
+ case emeOtr:
+ return ExplicitEncryptionType.otr;
+ case emeLegacyOpenPGP:
+ return ExplicitEncryptionType.legacyOpenPGP;
+ case emeOpenPGP:
+ return ExplicitEncryptionType.openPGP;
+ case emeOmemo:
+ return ExplicitEncryptionType.omemo;
+ case emeOmemo1:
+ return ExplicitEncryptionType.omemo1;
+ case emeOmemo2:
+ return ExplicitEncryptionType.omemo2;
+ default:
+ return ExplicitEncryptionType.unknown;
+ }
}
-}
-ExplicitEncryptionType _explicitEncryptionTypeFromString(String str) {
- switch (str) {
- case emeOtr:
- return ExplicitEncryptionType.otr;
- case emeLegacyOpenPGP:
- return ExplicitEncryptionType.legacyOpenPGP;
- case emeOpenPGP:
- return ExplicitEncryptionType.openPGP;
- case emeOmemo:
- return ExplicitEncryptionType.omemo;
- case emeOmemo1:
- return ExplicitEncryptionType.omemo1;
- case emeOmemo2:
- return ExplicitEncryptionType.omemo2;
- default:
- return ExplicitEncryptionType.unknown;
+ String toNamespace() {
+ switch (this) {
+ case ExplicitEncryptionType.otr:
+ return emeOtr;
+ case ExplicitEncryptionType.legacyOpenPGP:
+ return emeLegacyOpenPGP;
+ case ExplicitEncryptionType.openPGP:
+ return emeOpenPGP;
+ case ExplicitEncryptionType.omemo:
+ return emeOmemo;
+ case ExplicitEncryptionType.omemo1:
+ return emeOmemo1;
+ case ExplicitEncryptionType.omemo2:
+ return emeOmemo2;
+ case ExplicitEncryptionType.unknown:
+ return '';
+ }
}
-}
-/// Create an element with [type] indicating which type of encryption was
-/// used.
-XMLNode buildEmeElement(ExplicitEncryptionType type) {
- return XMLNode.xmlns(
- tag: 'encryption',
- xmlns: emeXmlns,
- attributes: {
- 'namespace': _explicitEncryptionTypeToString(type),
- },
- );
+ /// Create an element with an xmlns indicating what type of encryption was
+ /// used.
+ XMLNode toXML() {
+ return XMLNode.xmlns(
+ tag: 'encryption',
+ xmlns: emeXmlns,
+ attributes: {
+ 'namespace': toNamespace(),
+ },
+ );
+ }
}
class EmeManager extends XmppManagerBase {
@@ -91,10 +91,11 @@ class EmeManager extends XmppManagerBase {
) async {
final encryption = message.firstTag('encryption', xmlns: emeXmlns)!;
- return state.copyWith(
- encryptionType: _explicitEncryptionTypeFromString(
- encryption.attributes['namespace']! as String,
- ),
- );
+ return state
+ ..extensions.set(
+ ExplicitEncryptionType.fromNamespace(
+ encryption.attributes['namespace']! as String,
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0384/types.dart b/packages/moxxmpp/lib/src/xeps/xep_0384/types.dart
index 0b31d23..038598c 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0384/types.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0384/types.dart
@@ -1,6 +1,21 @@
+import 'package:omemo_dart/omemo_dart.dart';
+
/// A simple wrapper class for defining elements that should not be encrypted.
class DoNotEncrypt {
const DoNotEncrypt(this.tag, this.xmlns);
+
+ /// The tag of the element.
final String tag;
+
+ /// The xmlns attribute of the element.
final String xmlns;
}
+
+/// An encryption error caused by OMEMO.
+class OmemoEncryptionError {
+ const OmemoEncryptionError(this.jids, this.devices);
+
+ /// See omemo_dart's EncryptionResult for info on these fields.
+ final Map jids;
+ final Map devices;
+}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0384/xep_0384.dart b/packages/moxxmpp/lib/src/xeps/xep_0384/xep_0384.dart
index 63b7397..bdf618d 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0384/xep_0384.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0384/xep_0384.dart
@@ -16,6 +16,7 @@ import 'package:moxxmpp/src/xeps/xep_0030/types.dart';
import 'package:moxxmpp/src/xeps/xep_0030/xep_0030.dart';
import 'package:moxxmpp/src/xeps/xep_0060/errors.dart';
import 'package:moxxmpp/src/xeps/xep_0060/xep_0060.dart';
+import 'package:moxxmpp/src/xeps/xep_0203.dart';
import 'package:moxxmpp/src/xeps/xep_0280.dart';
import 'package:moxxmpp/src/xeps/xep_0334.dart';
import 'package:moxxmpp/src/xeps/xep_0380.dart';
@@ -276,7 +277,7 @@ abstract class BaseOmemoManager extends XmppManagerBase {
// Add a storage hint in case this is a message
// Taken from the example at
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
- MessageProcessingHint.store.toXml(),
+ MessageProcessingHint.store.toXML(),
],
),
awaitable: false,
@@ -363,19 +364,18 @@ abstract class BaseOmemoManager extends XmppManagerBase {
logger.finest('Encryption done');
if (!result.isSuccess(2)) {
- final other = Map.from(state.other);
- other['encryption_error_jids'] = result.jidEncryptionErrors;
- other['encryption_error_devices'] = result.deviceEncryptionErrors;
- return state.copyWith(
- other: other,
+ return state
+ ..cancel = true
// If we have no device list for toJid, then the contact most likely does not
// support OMEMO:2
- cancelReason: result.jidEncryptionErrors[toJid.toString()]
+ ..cancelReason = result.jidEncryptionErrors[toJid.toString()]
is NoKeyMaterialAvailableException
? OmemoNotSupportedForContactException()
- : UnknownOmemoError(),
- cancel: true,
- );
+ : UnknownOmemoError()
+ ..encryptionError = OmemoEncryptionError(
+ result.jidEncryptionErrors,
+ result.deviceEncryptionErrors,
+ );
}
final encrypted = _buildEncryptedElement(
@@ -389,19 +389,16 @@ abstract class BaseOmemoManager extends XmppManagerBase {
if (stanza.tag == 'message') {
children
// Add EME data
- ..add(buildEmeElement(ExplicitEncryptionType.omemo2))
+ ..add(ExplicitEncryptionType.omemo2.toXML())
// Add a storage hint in case this is a message
// Taken from the example at
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
- ..add(MessageProcessingHint.store.toXml());
+ ..add(MessageProcessingHint.store.toXML());
}
- return state.copyWith(
- stanza: state.stanza.copyWith(
- children: children,
- ),
- encrypted: true,
- );
+ return state
+ ..stanza = state.stanza.copyWith(children: children)
+ ..encrypted = true;
}
/// This function is called whenever a message is to be encrypted. If it returns true,
@@ -444,17 +441,19 @@ abstract class BaseOmemoManager extends XmppManagerBase {
OmemoIncomingStanza(
fromJid.toString(),
sid,
- state.delayedDelivery?.timestamp.millisecondsSinceEpoch ??
+ state.extensions
+ .get()
+ ?.timestamp
+ .millisecondsSinceEpoch ??
DateTime.now().millisecondsSinceEpoch,
keys,
payloadElement?.innerText(),
),
);
- final other = Map.from(state.other);
var children = stanza.children;
if (result.error != null) {
- other['encryption_error'] = result.error;
+ state.encryptionError = result.error;
} else {
children = stanza.children
.where(
@@ -471,11 +470,9 @@ abstract class BaseOmemoManager extends XmppManagerBase {
envelope = XMLNode.fromString(result.payload!);
} on XmlParserException catch (_) {
logger.warning('Failed to parse envelope payload: ${result.payload!}');
- other['encryption_error'] = InvalidEnvelopePayloadException();
- return state.copyWith(
- encrypted: true,
- other: other,
- );
+ return state
+ ..encrypted = true
+ ..encryptionError = InvalidEnvelopePayloadException();
}
final envelopeChildren = envelope.firstTag('content')?.children;
@@ -489,13 +486,13 @@ abstract class BaseOmemoManager extends XmppManagerBase {
}
if (!checkAffixElements(envelope, stanza.from!, ourJid)) {
- other['encryption_error'] = InvalidAffixElementsException();
+ state.encryptionError = InvalidAffixElementsException();
}
}
- return state.copyWith(
- encrypted: true,
- stanza: Stanza(
+ return state
+ ..encrypted = true
+ ..stanza = Stanza(
to: stanza.to,
from: stanza.from,
id: stanza.id,
@@ -503,9 +500,7 @@ abstract class BaseOmemoManager extends XmppManagerBase {
children: children,
tag: stanza.tag,
attributes: Map.from(stanza.attributes),
- ),
- other: other,
- );
+ );
}
/// Convenience function that attempts to retrieve the raw XML payload from the
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0385.dart b/packages/moxxmpp/lib/src/xeps/xep_0385.dart
index fdc6215..bbf66d0 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0385.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0385.dart
@@ -98,7 +98,7 @@ class SIMSManager extends XmppManagerBase {
final references = message.findTags('reference', xmlns: referenceXmlns);
for (final ref in references) {
final sims = ref.firstTag('media-sharing', xmlns: simsXmlns);
- if (sims != null) return state.copyWith(sims: parseSIMSElement(sims));
+ if (sims != null) return state..extensions.set(parseSIMSElement(sims));
}
return state;
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0424.dart b/packages/moxxmpp/lib/src/xeps/xep_0424.dart
index a9cfc6f..ca5bc62 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0424.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0424.dart
@@ -47,11 +47,12 @@ class MessageRetractionManager extends XmppManagerBase {
final isFallbackBody =
message.firstTag('fallback', xmlns: fallbackIndicationXmlns) != null;
- return state.copyWith(
- messageRetraction: MessageRetractionData(
- applyTo.attributes['id']! as String,
- isFallbackBody ? message.firstTag('body')?.innerText() : null,
- ),
- );
+ return state
+ ..extensions.set(
+ MessageRetractionData(
+ applyTo.attributes['id']! as String,
+ isFallbackBody ? message.firstTag('body')?.innerText() : null,
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0444.dart b/packages/moxxmpp/lib/src/xeps/xep_0444.dart
index 15448ea..0e8f9ac 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0444.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0444.dart
@@ -55,14 +55,15 @@ class MessageReactionsManager extends XmppManagerBase {
) async {
final reactionsElement =
message.firstTag('reactions', xmlns: messageReactionsXmlns)!;
- return state.copyWith(
- messageReactions: MessageReactions(
- reactionsElement.attributes['id']! as String,
- reactionsElement.children
- .where((c) => c.tag == 'reaction')
- .map((c) => c.innerText())
- .toList(),
- ),
- );
+ return state
+ ..extensions.set(
+ MessageReactions(
+ reactionsElement.attributes['id']! as String,
+ reactionsElement.children
+ .where((c) => c.tag == 'reaction')
+ .map((c) => c.innerText())
+ .toList(),
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0447.dart b/packages/moxxmpp/lib/src/xeps/xep_0447.dart
index 81ee7d8..f9c8cff 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0447.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0447.dart
@@ -135,10 +135,9 @@ class SFSManager extends XmppManagerBase {
) async {
final sfs = message.firstTag('file-sharing', xmlns: sfsXmlns)!;
- return state.copyWith(
- sfs: StatelessFileSharingData.fromXML(
- sfs,
- ),
- );
+ return state
+ ..extensions.set(
+ StatelessFileSharingData.fromXML(sfs),
+ );
}
}
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0449.dart b/packages/moxxmpp/lib/src/xeps/xep_0449.dart
index fb95432..1f95556 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0449.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0449.dart
@@ -227,6 +227,13 @@ class StickerPack {
}
}
+class StickersData {
+ const StickersData(this.stickerPackId);
+
+ /// The id of the sticker pack the referenced sticker is from.
+ final String stickerPackId;
+}
+
class StickersManager extends XmppManagerBase {
StickersManager() : super(stickersManager);
@@ -249,9 +256,10 @@ class StickersManager extends XmppManagerBase {
StanzaHandlerData state,
) async {
final sticker = stanza.firstTag('sticker', xmlns: stickersXmlns)!;
- return state.copyWith(
- stickerPackId: sticker.attributes['pack']! as String,
- );
+ return state
+ ..extensions.set(
+ StickersData(sticker.attributes['pack']! as String),
+ );
}
/// Publishes the StickerPack [pack] to the PubSub node of [jid]. If specified, then
diff --git a/packages/moxxmpp/lib/src/xeps/xep_0461.dart b/packages/moxxmpp/lib/src/xeps/xep_0461.dart
index 11ee5bf..0415d6f 100644
--- a/packages/moxxmpp/lib/src/xeps/xep_0461.dart
+++ b/packages/moxxmpp/lib/src/xeps/xep_0461.dart
@@ -103,13 +103,14 @@ class MessageRepliesManager extends XmppManagerBase {
end = int.parse(body.attributes['end']! as String);
}
- return state.copyWith(
- reply: ReplyData(
- id: id,
- to: to,
- start: start,
- end: end,
- ),
- );
+ return state
+ ..extensions.set(
+ ReplyData(
+ id: id,
+ to: to,
+ start: start,
+ end: end,
+ ),
+ );
}
}
diff --git a/packages/moxxmpp/test/stanzahandler_test.dart b/packages/moxxmpp/test/stanzahandler_test.dart
index 3c3bae8..1ff4142 100644
--- a/packages/moxxmpp/test/stanzahandler_test.dart
+++ b/packages/moxxmpp/test/stanzahandler_test.dart
@@ -1,4 +1,5 @@
import 'package:moxxmpp/moxxmpp.dart';
+import 'package:moxxmpp/src/util/typed_map.dart';
import 'package:test/test.dart';
final stanza1 = Stanza.iq(
@@ -16,8 +17,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
);
@@ -38,8 +39,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagXmlns: 'owo',
);
@@ -59,8 +60,8 @@ void main() {
return StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
);
},
stanzaTag: 'iq',
@@ -77,8 +78,8 @@ void main() {
StanzaHandlerData(
false,
false,
- null,
stanza2,
+ TypedMap(),
),
);
expect(run, true);
@@ -89,8 +90,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagName: 'tag',
);
@@ -107,8 +108,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagName: 'tag',
stanzaTag: 'iq',
@@ -127,8 +128,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
xmlns: componentAcceptXmlns,
);
@@ -147,8 +148,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagName: '1',
priority: 100,
@@ -157,8 +158,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagName: '2',
),
@@ -166,8 +167,8 @@ void main() {
callback: (stanza, _) async => StanzaHandlerData(
true,
false,
- null,
stanza,
+ TypedMap(),
),
tagName: '3',
priority: 50,
diff --git a/packages/moxxmpp/test/xeps/xep_0198_test.dart b/packages/moxxmpp/test/xeps/xep_0198_test.dart
index 1ba8b78..07c118a 100644
--- a/packages/moxxmpp/test/xeps/xep_0198_test.dart
+++ b/packages/moxxmpp/test/xeps/xep_0198_test.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:moxxmpp/moxxmpp.dart';
+import 'package:moxxmpp/src/util/typed_map.dart';
import 'package:test/test.dart';
import '../helpers/logging.dart';
import '../helpers/xmpp.dart';
@@ -15,8 +16,8 @@ Future runIncomingStanzaHandlers(
StanzaHandlerData(
false,
false,
- null,
stanza,
+ TypedMap(),
),
);
}
@@ -34,8 +35,8 @@ Future runOutgoingStanzaHandlers(
StanzaHandlerData(
false,
false,
- null,
stanza,
+ TypedMap(),
),
);
}
diff --git a/packages/moxxmpp/test/xmpp_test.dart b/packages/moxxmpp/test/xmpp_test.dart
index 50675f4..21d80d0 100644
--- a/packages/moxxmpp/test/xmpp_test.dart
+++ b/packages/moxxmpp/test/xmpp_test.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:moxxmpp/moxxmpp.dart';
+import 'package:moxxmpp/src/util/typed_map.dart';
import 'package:test/test.dart';
import 'helpers/logging.dart';
import 'helpers/xmpp.dart';
@@ -78,8 +79,8 @@ Future testRosterManager(
StanzaHandlerData(
false,
false,
- null,
stanza,
+ TypedMap(),
),
);
}
@@ -335,8 +336,8 @@ void main() {
StanzaHandlerData(
false,
false,
- null,
maliciousStanza,
+ TypedMap(),
),
);
}