feat: Implement XEP-0308

This commit is contained in:
PapaTutuWawa 2022-11-26 15:08:20 +01:00
parent 138edffb0a
commit 14c48bcc64
7 changed files with 103 additions and 8 deletions

View File

@ -74,6 +74,7 @@ class MessageEvent extends XmppEvent {
this.funReplacement, this.funReplacement,
this.funCancellation, this.funCancellation,
this.messageRetraction, this.messageRetraction,
this.messageCorrectionId,
}); });
final StanzaError? error; final StanzaError? error;
final String body; final String body;
@ -95,6 +96,7 @@ class MessageEvent extends XmppEvent {
final String? funCancellation; final String? funCancellation;
final bool encrypted; final bool encrypted;
final MessageRetractionData? messageRetraction; final MessageRetractionData? messageRetraction;
final String? messageCorrectionId;
final Map<String, dynamic> other; final Map<String, dynamic> other;
} }

View File

@ -59,6 +59,8 @@ class StanzaHandlerData with _$StanzaHandlerData {
// If non-null, then it indicates the origin Id of the message that should be // If non-null, then it indicates the origin Id of the message that should be
// retracted // retracted
MessageRetractionData? messageRetraction, MessageRetractionData? messageRetraction,
// If non-null, then the message is a correction for the specified stanza Id
String? lastMessageCorrectionSid,
} }
) = _StanzaHandlerData; ) = _StanzaHandlerData;
} }

View File

@ -58,7 +58,8 @@ mixin _$StanzaHandlerData {
throw _privateConstructorUsedError; // If non-null, then it indicates the origin Id of the message that should be throw _privateConstructorUsedError; // If non-null, then it indicates the origin Id of the message that should be
// retracted // retracted
MessageRetractionData? get messageRetraction => MessageRetractionData? get messageRetraction =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError; // If non-null, then the message is a correction for the specified stanza Id
String? get lastMessageCorrectionSid => throw _privateConstructorUsedError;
@JsonKey(ignore: true) @JsonKey(ignore: true)
$StanzaHandlerDataCopyWith<StanzaHandlerData> get copyWith => $StanzaHandlerDataCopyWith<StanzaHandlerData> get copyWith =>
@ -92,7 +93,8 @@ abstract class $StanzaHandlerDataCopyWith<$Res> {
ExplicitEncryptionType? encryptionType, ExplicitEncryptionType? encryptionType,
DelayedDelivery? delayedDelivery, DelayedDelivery? delayedDelivery,
Map<String, dynamic> other, Map<String, dynamic> other,
MessageRetractionData? messageRetraction}); MessageRetractionData? messageRetraction,
String? lastMessageCorrectionSid});
} }
/// @nodoc /// @nodoc
@ -128,6 +130,7 @@ class _$StanzaHandlerDataCopyWithImpl<$Res>
Object? delayedDelivery = freezed, Object? delayedDelivery = freezed,
Object? other = freezed, Object? other = freezed,
Object? messageRetraction = freezed, Object? messageRetraction = freezed,
Object? lastMessageCorrectionSid = freezed,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
done: done == freezed done: done == freezed
@ -218,6 +221,10 @@ class _$StanzaHandlerDataCopyWithImpl<$Res>
? _value.messageRetraction ? _value.messageRetraction
: messageRetraction // ignore: cast_nullable_to_non_nullable : messageRetraction // ignore: cast_nullable_to_non_nullable
as MessageRetractionData?, as MessageRetractionData?,
lastMessageCorrectionSid: lastMessageCorrectionSid == freezed
? _value.lastMessageCorrectionSid
: lastMessageCorrectionSid // ignore: cast_nullable_to_non_nullable
as String?,
)); ));
} }
} }
@ -251,7 +258,8 @@ abstract class _$$_StanzaHandlerDataCopyWith<$Res>
ExplicitEncryptionType? encryptionType, ExplicitEncryptionType? encryptionType,
DelayedDelivery? delayedDelivery, DelayedDelivery? delayedDelivery,
Map<String, dynamic> other, Map<String, dynamic> other,
MessageRetractionData? messageRetraction}); MessageRetractionData? messageRetraction,
String? lastMessageCorrectionSid});
} }
/// @nodoc /// @nodoc
@ -289,6 +297,7 @@ class __$$_StanzaHandlerDataCopyWithImpl<$Res>
Object? delayedDelivery = freezed, Object? delayedDelivery = freezed,
Object? other = freezed, Object? other = freezed,
Object? messageRetraction = freezed, Object? messageRetraction = freezed,
Object? lastMessageCorrectionSid = freezed,
}) { }) {
return _then(_$_StanzaHandlerData( return _then(_$_StanzaHandlerData(
done == freezed done == freezed
@ -379,6 +388,10 @@ class __$$_StanzaHandlerDataCopyWithImpl<$Res>
? _value.messageRetraction ? _value.messageRetraction
: messageRetraction // ignore: cast_nullable_to_non_nullable : messageRetraction // ignore: cast_nullable_to_non_nullable
as MessageRetractionData?, as MessageRetractionData?,
lastMessageCorrectionSid: lastMessageCorrectionSid == freezed
? _value.lastMessageCorrectionSid
: lastMessageCorrectionSid // ignore: cast_nullable_to_non_nullable
as String?,
)); ));
} }
} }
@ -404,7 +417,8 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
this.encryptionType, this.encryptionType,
this.delayedDelivery, this.delayedDelivery,
final Map<String, dynamic> other = const <String, dynamic>{}, final Map<String, dynamic> other = const <String, dynamic>{},
this.messageRetraction}) this.messageRetraction,
this.lastMessageCorrectionSid})
: _other = other; : _other = other;
// Indicates to the runner that processing is now done. This means that all // Indicates to the runner that processing is now done. This means that all
@ -484,10 +498,13 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
// retracted // retracted
@override @override
final MessageRetractionData? messageRetraction; final MessageRetractionData? messageRetraction;
// If non-null, then the message is a correction for the specified stanza Id
@override
final String? lastMessageCorrectionSid;
@override @override
String toString() { String toString() {
return 'StanzaHandlerData(done: $done, cancel: $cancel, cancelReason: $cancelReason, stanza: $stanza, retransmitted: $retransmitted, sims: $sims, sfs: $sfs, oob: $oob, stableId: $stableId, reply: $reply, chatState: $chatState, isCarbon: $isCarbon, deliveryReceiptRequested: $deliveryReceiptRequested, isMarkable: $isMarkable, fun: $fun, funReplacement: $funReplacement, funCancellation: $funCancellation, encrypted: $encrypted, encryptionType: $encryptionType, delayedDelivery: $delayedDelivery, other: $other, messageRetraction: $messageRetraction)'; return 'StanzaHandlerData(done: $done, cancel: $cancel, cancelReason: $cancelReason, stanza: $stanza, retransmitted: $retransmitted, sims: $sims, sfs: $sfs, oob: $oob, stableId: $stableId, reply: $reply, chatState: $chatState, isCarbon: $isCarbon, deliveryReceiptRequested: $deliveryReceiptRequested, isMarkable: $isMarkable, fun: $fun, funReplacement: $funReplacement, funCancellation: $funCancellation, encrypted: $encrypted, encryptionType: $encryptionType, delayedDelivery: $delayedDelivery, other: $other, messageRetraction: $messageRetraction, lastMessageCorrectionSid: $lastMessageCorrectionSid)';
} }
@override @override
@ -525,7 +542,9 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
.equals(other.delayedDelivery, delayedDelivery) && .equals(other.delayedDelivery, delayedDelivery) &&
const DeepCollectionEquality().equals(other._other, this._other) && const DeepCollectionEquality().equals(other._other, this._other) &&
const DeepCollectionEquality() const DeepCollectionEquality()
.equals(other.messageRetraction, messageRetraction)); .equals(other.messageRetraction, messageRetraction) &&
const DeepCollectionEquality().equals(
other.lastMessageCorrectionSid, lastMessageCorrectionSid));
} }
@override @override
@ -552,7 +571,8 @@ class _$_StanzaHandlerData implements _StanzaHandlerData {
const DeepCollectionEquality().hash(encryptionType), const DeepCollectionEquality().hash(encryptionType),
const DeepCollectionEquality().hash(delayedDelivery), const DeepCollectionEquality().hash(delayedDelivery),
const DeepCollectionEquality().hash(_other), const DeepCollectionEquality().hash(_other),
const DeepCollectionEquality().hash(messageRetraction) const DeepCollectionEquality().hash(messageRetraction),
const DeepCollectionEquality().hash(lastMessageCorrectionSid)
]); ]);
@JsonKey(ignore: true) @JsonKey(ignore: true)
@ -582,7 +602,8 @@ abstract class _StanzaHandlerData implements StanzaHandlerData {
final ExplicitEncryptionType? encryptionType, final ExplicitEncryptionType? encryptionType,
final DelayedDelivery? delayedDelivery, final DelayedDelivery? delayedDelivery,
final Map<String, dynamic> other, final Map<String, dynamic> other,
final MessageRetractionData? messageRetraction}) = _$_StanzaHandlerData; final MessageRetractionData? messageRetraction,
final String? lastMessageCorrectionSid}) = _$_StanzaHandlerData;
@override // Indicates to the runner that processing is now done. This means that all @override // Indicates to the runner that processing is now done. This means that all
// pre-processing is done and no other handlers should be consulted. // pre-processing is done and no other handlers should be consulted.
@ -635,6 +656,8 @@ abstract class _StanzaHandlerData implements StanzaHandlerData {
@override // If non-null, then it indicates the origin Id of the message that should be @override // If non-null, then it indicates the origin Id of the message that should be
// retracted // retracted
MessageRetractionData? get messageRetraction; MessageRetractionData? get messageRetraction;
@override // If non-null, then the message is a correction for the specified stanza Id
String? get lastMessageCorrectionSid;
@override @override
@JsonKey(ignore: true) @JsonKey(ignore: true)
_$$_StanzaHandlerDataCopyWith<_$_StanzaHandlerData> get copyWith => _$$_StanzaHandlerDataCopyWith<_$_StanzaHandlerData> get copyWith =>

View File

@ -25,3 +25,4 @@ const emeManager = 'org.moxxmpp.ememanager';
const cryptographicHashManager = 'org.moxxmpp.cryptographichashmanager'; const cryptographicHashManager = 'org.moxxmpp.cryptographichashmanager';
const delayedDeliveryManager = 'org.moxxmpp.delayeddeliverymanager'; const delayedDeliveryManager = 'org.moxxmpp.delayeddeliverymanager';
const messageRetractionManager = 'org.moxxmpp.messageretractionmanager'; const messageRetractionManager = 'org.moxxmpp.messageretractionmanager';
const lastMessageCorrectionManager = 'org.moxxmpp.lastmessagecorrectionmanager';

View File

@ -11,6 +11,7 @@ import 'package:moxxmpp/src/xeps/staging/file_upload_notification.dart';
import 'package:moxxmpp/src/xeps/xep_0066.dart'; import 'package:moxxmpp/src/xeps/xep_0066.dart';
import 'package:moxxmpp/src/xeps/xep_0085.dart'; import 'package:moxxmpp/src/xeps/xep_0085.dart';
import 'package:moxxmpp/src/xeps/xep_0184.dart'; import 'package:moxxmpp/src/xeps/xep_0184.dart';
import 'package:moxxmpp/src/xeps/xep_0308.dart';
import 'package:moxxmpp/src/xeps/xep_0333.dart'; import 'package:moxxmpp/src/xeps/xep_0333.dart';
import 'package:moxxmpp/src/xeps/xep_0359.dart'; import 'package:moxxmpp/src/xeps/xep_0359.dart';
import 'package:moxxmpp/src/xeps/xep_0424.dart'; import 'package:moxxmpp/src/xeps/xep_0424.dart';
@ -36,6 +37,7 @@ class MessageDetails {
this.funCancellation, this.funCancellation,
this.shouldEncrypt = false, this.shouldEncrypt = false,
this.messageRetraction, this.messageRetraction,
this.lastMessageCorrectionId,
}); });
final String to; final String to;
final String? body; final String? body;
@ -53,6 +55,7 @@ class MessageDetails {
final String? funCancellation; final String? funCancellation;
final bool shouldEncrypt; final bool shouldEncrypt;
final MessageRetractionData? messageRetraction; final MessageRetractionData? messageRetraction;
final String? lastMessageCorrectionId;
} }
class MessageManager extends XmppManagerBase { class MessageManager extends XmppManagerBase {
@ -98,6 +101,7 @@ class MessageManager extends XmppManagerBase {
funCancellation: state.funCancellation, funCancellation: state.funCancellation,
encrypted: state.encrypted, encrypted: state.encrypted,
messageRetraction: state.messageRetraction, messageRetraction: state.messageRetraction,
messageCorrectionId: state.lastMessageCorrectionSid,
other: state.other, other: state.other,
error: StanzaError.fromStanza(message), error: StanzaError.fromStanza(message),
),); ),);
@ -249,6 +253,14 @@ class MessageManager extends XmppManagerBase {
); );
} }
} }
if (details.lastMessageCorrectionId != null) {
stanza.addChild(
makeLastMessageCorrectionEdit(
details.lastMessageCorrectionId!,
),
);
}
getAttributes().sendStanza(stanza, awaitable: false); getAttributes().sendStanza(stanza, awaitable: false);
} }

View File

@ -76,6 +76,9 @@ const hashSha3512 = 'sha3-512';
const hashBlake2b256 = 'blake2b-256'; const hashBlake2b256 = 'blake2b-256';
const hashBlake2b512 = 'blake2b-512'; const hashBlake2b512 = 'blake2b-512';
// XEP-0308
const lmcXmlns = 'urn:xmpp:message-correct:0';
// XEP-0333 // XEP-0333
const chatMarkersXmlns = 'urn:xmpp:chat-markers:0'; const chatMarkersXmlns = 'urn:xmpp:chat-markers:0';

View File

@ -0,0 +1,52 @@
import 'package:moxxmpp/src/managers/base.dart';
import 'package:moxxmpp/src/managers/data.dart';
import 'package:moxxmpp/src/managers/handlers.dart';
import 'package:moxxmpp/src/managers/namespaces.dart';
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: <String, String>{
'id': id,
},
);
}
class LastMessageCorrectionManager extends XmppManagerBase {
@override
String getName() => 'LastMessageCorrectionManager';
@override
String getId() => lastMessageCorrectionManager;
@override
List<String> getDiscoFeatures() => [ lmcXmlns ];
@override
List<StanzaHandler> getIncomingStanzaHandlers() => [
StanzaHandler(
stanzaTag: 'message',
tagName: 'reply',
tagXmlns: replyXmlns,
callback: _onMessage,
// Before the message handler
priority: -99,
)
];
@override
Future<bool> isSupported() async => true;
Future<StanzaHandlerData> _onMessage(Stanza stanza, StanzaHandlerData state) async {
final edit = stanza.firstTag('replace', xmlns: lmcXmlns);
if (edit == null) return state;
return state.copyWith(
lastMessageCorrectionSid: edit.attributes['id']! as String,
);
}
}