feat(all): Move all managers to the new data system
This commit is contained in:
parent
8270185027
commit
79d7e3ba64
@ -27,7 +27,9 @@ import 'package:moxxmpp/src/stanza.dart';
|
|||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
import 'package:moxxmpp/src/types/result.dart';
|
import 'package:moxxmpp/src/types/result.dart';
|
||||||
import 'package:moxxmpp/src/util/queue.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_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_0198/xep_0198.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0352.dart';
|
import 'package:moxxmpp/src/xeps/xep_0352.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
@ -474,8 +476,8 @@ class XmppConnection {
|
|||||||
initial: StanzaHandlerData(
|
initial: StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
newStanza,
|
newStanza,
|
||||||
|
TypedMap(),
|
||||||
encrypted: details.encrypted,
|
encrypted: details.encrypted,
|
||||||
forceEncryption: details.forceEncryption,
|
forceEncryption: details.forceEncryption,
|
||||||
),
|
),
|
||||||
@ -531,14 +533,15 @@ class XmppConnection {
|
|||||||
|
|
||||||
// Run post-send handlers
|
// Run post-send handlers
|
||||||
_log.fine('Running post stanza handlers..');
|
_log.fine('Running post stanza handlers..');
|
||||||
|
final extensions = TypedMap()
|
||||||
|
..set(StreamManagementData(details.excludeFromStreamManagement));
|
||||||
await _runOutgoingPostStanzaHandlers(
|
await _runOutgoingPostStanzaHandlers(
|
||||||
newStanza,
|
newStanza,
|
||||||
initial: StanzaHandlerData(
|
initial: StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
newStanza,
|
newStanza,
|
||||||
excludeFromStreamManagement: details.excludeFromStreamManagement,
|
extensions,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_log.fine('Done');
|
_log.fine('Done');
|
||||||
@ -653,7 +656,7 @@ class XmppConnection {
|
|||||||
Stanza stanza, {
|
Stanza stanza, {
|
||||||
StanzaHandlerData? initial,
|
StanzaHandlerData? initial,
|
||||||
}) async {
|
}) async {
|
||||||
var state = initial ?? StanzaHandlerData(false, false, null, stanza);
|
var state = initial ?? StanzaHandlerData(false, false, stanza, TypedMap());
|
||||||
for (final handler in handlers) {
|
for (final handler in handlers) {
|
||||||
if (handler.matches(state.stanza)) {
|
if (handler.matches(state.stanza)) {
|
||||||
state = await handler.callback(state.stanza, state);
|
state = await handler.callback(state.stanza, state);
|
||||||
@ -728,7 +731,7 @@ class XmppConnection {
|
|||||||
// it.
|
// it.
|
||||||
final incomingPreHandlers = await _runIncomingPreStanzaHandlers(stanza);
|
final incomingPreHandlers = await _runIncomingPreStanzaHandlers(stanza);
|
||||||
final prefix = incomingPreHandlers.encrypted &&
|
final prefix = incomingPreHandlers.encrypted &&
|
||||||
incomingPreHandlers.other['encryption_error'] == null
|
incomingPreHandlers.encryptionError == null
|
||||||
? '(Encrypted) '
|
? '(Encrypted) '
|
||||||
: '';
|
: '';
|
||||||
_log.finest('<== $prefix${incomingPreHandlers.stanza.toXml()}');
|
_log.finest('<== $prefix${incomingPreHandlers.stanza.toXml()}');
|
||||||
@ -747,10 +750,10 @@ class XmppConnection {
|
|||||||
initial: StanzaHandlerData(
|
initial: StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
incomingPreHandlers.cancel,
|
incomingPreHandlers.cancel,
|
||||||
incomingPreHandlers.cancelReason,
|
|
||||||
incomingPreHandlers.stanza,
|
incomingPreHandlers.stanza,
|
||||||
|
incomingPreHandlers.extensions,
|
||||||
encrypted: incomingPreHandlers.encrypted,
|
encrypted: incomingPreHandlers.encrypted,
|
||||||
other: incomingPreHandlers.other,
|
cancelReason: incomingPreHandlers.cancelReason,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!incomingHandlers.done) {
|
if (!incomingHandlers.done) {
|
||||||
|
@ -1,82 +1,45 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0066.dart';
|
import 'package:moxxmpp/src/util/typed_map.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';
|
|
||||||
|
|
||||||
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
|
/// Indicates to the runner that processing is now done. This means that all
|
||||||
class StanzaHandlerData with _$StanzaHandlerData {
|
/// pre-processing is done and no other handlers should be consulted.
|
||||||
factory StanzaHandlerData(
|
bool done;
|
||||||
// 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,
|
|
||||||
|
|
||||||
// XEP-0359 <origin-id />'s id attribute, if available.
|
/// Indicates to the runner that processing is to be cancelled and no further handlers
|
||||||
String? originId,
|
/// should run. The stanza also will not be sent.
|
||||||
|
bool cancel;
|
||||||
|
|
||||||
|
/// 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;
|
||||||
|
|
||||||
// XEP-0359 <stanza-id /> elements, if available.
|
|
||||||
List<StanzaId>? 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
|
// 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
|
// would not normally. In the case of OMEMO: If shouldEncrypt returns false
|
||||||
// but forceEncryption is true, then the OMEMO manager will try to encrypt
|
// but forceEncryption is true, then the OMEMO manager will try to encrypt
|
||||||
// to the JID anyway.
|
// to the JID anyway.
|
||||||
@Default(false) bool forceEncryption,
|
bool forceEncryption;
|
||||||
// The stated type of encryption used, if any was used
|
|
||||||
ExplicitEncryptionType? encryptionType,
|
/// Additional data from other managers.
|
||||||
// Delayed Delivery
|
final TypedMap extensions;
|
||||||
DelayedDelivery? delayedDelivery,
|
|
||||||
// This is for stanza handlers that are not part of the XMPP library but still need
|
|
||||||
// pass data around.
|
|
||||||
@Default(<String, dynamic>{}) Map<String, dynamic> 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;
|
|
||||||
}
|
}
|
||||||
|
@ -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_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_0280.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0308.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_0334.dart';
|
import 'package:moxxmpp/src/xeps/xep_0334.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0359.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_0424.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0444.dart';
|
import 'package:moxxmpp/src/xeps/xep_0444.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0446.dart';
|
import 'package:moxxmpp/src/xeps/xep_0446.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0447.dart';
|
import 'package:moxxmpp/src/xeps/xep_0447.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0448.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';
|
import 'package:moxxmpp/src/xeps/xep_0461.dart';
|
||||||
|
|
||||||
/// Data used to build a message stanza.
|
/// Data used to build a message stanza.
|
||||||
@ -100,7 +103,7 @@ class MessageManager extends XmppManagerBase {
|
|||||||
final hints = List<MessageProcessingHint>.empty(growable: true);
|
final hints = List<MessageProcessingHint>.empty(growable: true);
|
||||||
for (final element
|
for (final element
|
||||||
in message.findTagsByXmlns(messageProcessingHintsXmlns)) {
|
in message.findTagsByXmlns(messageProcessingHintsXmlns)) {
|
||||||
hints.add(messageProcessingHintFromXml(element));
|
hints.add(MessageProcessingHint.fromName(element.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
getAttributes().sendEvent(
|
getAttributes().sendEvent(
|
||||||
@ -109,32 +112,37 @@ class MessageManager extends XmppManagerBase {
|
|||||||
fromJid: JID.fromString(message.attributes['from']! as String),
|
fromJid: JID.fromString(message.attributes['from']! as String),
|
||||||
toJid: JID.fromString(message.attributes['to']! as String),
|
toJid: JID.fromString(message.attributes['to']! as String),
|
||||||
sid: message.attributes['id']! as String,
|
sid: message.attributes['id']! as String,
|
||||||
originId: state.originId,
|
originId: state.extensions.get<StableIdData>()?.originId,
|
||||||
stanzaIds: state.stanzaIds,
|
stanzaIds: state.extensions.get<StableIdData>()?.stanzaIds,
|
||||||
isCarbon: state.isCarbon,
|
isCarbon: state.extensions.get<CarbonsData>()?.isCarbon ?? false,
|
||||||
deliveryReceiptRequested: state.deliveryReceiptRequested,
|
deliveryReceiptRequested: state.extensions
|
||||||
isMarkable: state.isMarkable,
|
.get<MessageDeliveryReceiptData>()
|
||||||
|
?.receiptRequested ??
|
||||||
|
false,
|
||||||
|
isMarkable: state.extensions.get<ChatMarkerData>()?.isMarkable ?? false,
|
||||||
type: message.attributes['type'] as String?,
|
type: message.attributes['type'] as String?,
|
||||||
oob: state.oob,
|
oob: state.extensions.get<OOBData>(),
|
||||||
sfs: state.sfs,
|
sfs: state.extensions.get<StatelessFileSharingData>(),
|
||||||
sims: state.sims,
|
sims: state.extensions.get<StatelessMediaSharingData>(),
|
||||||
reply: state.reply,
|
reply: state.extensions.get<ReplyData>(),
|
||||||
chatState: state.chatState,
|
chatState: state.extensions.get<ChatState>(),
|
||||||
fun: state.fun,
|
fun: state.extensions.get<FileUploadNotificationData>()?.metadata,
|
||||||
funReplacement: state.funReplacement,
|
funReplacement:
|
||||||
funCancellation: state.funCancellation,
|
state.extensions.get<FileUploadNotificationReplacementData>()?.id,
|
||||||
|
funCancellation:
|
||||||
|
state.extensions.get<FileUploadNotificationCancellationData>()?.id,
|
||||||
encrypted: state.encrypted,
|
encrypted: state.encrypted,
|
||||||
messageRetraction: state.messageRetraction,
|
messageRetraction: state.extensions.get<MessageRetractionData>(),
|
||||||
messageCorrectionId: state.lastMessageCorrectionSid,
|
messageCorrectionId: state.extensions.get<MessageRetractionData>()?.id,
|
||||||
messageReactions: state.messageReactions,
|
messageReactions: state.extensions.get<MessageReactions>(),
|
||||||
messageProcessingHints: hints.isEmpty ? null : hints,
|
messageProcessingHints: hints.isEmpty ? null : hints,
|
||||||
stickerPackId: state.stickerPackId,
|
stickerPackId: state.extensions.get<StickersData>()?.stickerPackId,
|
||||||
other: state.other,
|
other: {},
|
||||||
error: StanzaError.fromStanza(message),
|
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
|
/// 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.
|
/// 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"
|
/// 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.
|
/// child in the message stanza and set its id to originId.
|
||||||
void sendMessage(MessageDetails details) {
|
Future<void> sendMessage(MessageDetails details) async {
|
||||||
assert(
|
assert(
|
||||||
implies(
|
implies(
|
||||||
details.quoteBody != null,
|
details.quoteBody != null,
|
||||||
@ -216,7 +224,7 @@ class MessageManager extends XmppManagerBase {
|
|||||||
stanza.addChild(makeChatMarkerMarkable());
|
stanza.addChild(makeChatMarkerMarkable());
|
||||||
}
|
}
|
||||||
if (details.originId != null) {
|
if (details.originId != null) {
|
||||||
stanza.addChild(makeOriginIdElement(details.originId!));
|
stanza.addChild(StableIdData(details.originId, null).toOriginIdElement());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.sfs != null) {
|
if (details.sfs != null) {
|
||||||
@ -226,17 +234,13 @@ class MessageManager extends XmppManagerBase {
|
|||||||
if (source is StatelessFileSharingUrlSource &&
|
if (source is StatelessFileSharingUrlSource &&
|
||||||
details.setOOBFallbackBody) {
|
details.setOOBFallbackBody) {
|
||||||
// SFS recommends OOB as a fallback
|
// SFS recommends OOB as a fallback
|
||||||
stanza.addChild(constructOOBNode(OOBData(url: source.url)));
|
stanza.addChild(OOBData(source.url, null).toXML());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (details.chatState != null) {
|
if (details.chatState != null) {
|
||||||
stanza.addChild(
|
stanza.addChild(
|
||||||
// TODO(Unknown): Move this into xep_0085.dart
|
details.chatState!.toXML(),
|
||||||
XMLNode.xmlns(
|
|
||||||
tag: chatStateToString(details.chatState!),
|
|
||||||
xmlns: chatStateXmlns,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,9 +297,9 @@ class MessageManager extends XmppManagerBase {
|
|||||||
|
|
||||||
if (details.lastMessageCorrectionId != null) {
|
if (details.lastMessageCorrectionId != null) {
|
||||||
stanza.addChild(
|
stanza.addChild(
|
||||||
makeLastMessageCorrectionEdit(
|
LastMessageCorrectionData(
|
||||||
details.lastMessageCorrectionId!,
|
details.lastMessageCorrectionId!,
|
||||||
),
|
).toXML(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +309,7 @@ class MessageManager extends XmppManagerBase {
|
|||||||
|
|
||||||
if (details.messageProcessingHints != null) {
|
if (details.messageProcessingHints != null) {
|
||||||
for (final hint in details.messageProcessingHints!) {
|
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(
|
StanzaDetails(
|
||||||
stanza,
|
stanza,
|
||||||
awaitable: false,
|
awaitable: false,
|
||||||
|
@ -66,7 +66,7 @@ class PresenceManager extends XmppManagerBase {
|
|||||||
from: JID.fromString(presence.from!),
|
from: JID.fromString(presence.from!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -78,7 +78,7 @@ class PresenceManager extends XmppManagerBase {
|
|||||||
getAttributes().sendEvent(
|
getAttributes().sendEvent(
|
||||||
PresenceReceivedEvent(JID.fromString(presence.from!), presence),
|
PresenceReceivedEvent(JID.fromString(presence.from!), presence),
|
||||||
);
|
);
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
@ -145,7 +145,7 @@ class RosterManager extends XmppManagerBase {
|
|||||||
logger.warning(
|
logger.warning(
|
||||||
'Roster push invalid! Unexpected from attribute: ${stanza.toXml()}',
|
'Roster push invalid! Unexpected from attribute: ${stanza.toXml()}',
|
||||||
);
|
);
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final query = stanza.firstTag('query', xmlns: rosterXmlns)!;
|
final query = stanza.firstTag('query', xmlns: rosterXmlns)!;
|
||||||
@ -154,7 +154,7 @@ class RosterManager extends XmppManagerBase {
|
|||||||
|
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
logger.warning('Received empty roster push');
|
logger.warning('Received empty roster push');
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unawaited(
|
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
|
/// Shared code between requesting rosters without and with roster versioning, if
|
||||||
|
@ -7,9 +7,32 @@ import 'package:moxxmpp/src/stanza.dart';
|
|||||||
import 'package:moxxmpp/src/xeps/xep_0446.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
|
/// NOTE: Specified by https://github.com/PapaTutuWawa/custom-xeps/blob/master/xep-xxxx-file-upload-notifications.md
|
||||||
|
|
||||||
const fileUploadNotificationXmlns = 'proto:urn:xmpp:fun:0';
|
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 {
|
class FileUploadNotificationManager extends XmppManagerBase {
|
||||||
FileUploadNotificationManager() : super(fileUploadNotificationManager);
|
FileUploadNotificationManager() : super(fileUploadNotificationManager);
|
||||||
|
|
||||||
@ -47,10 +70,13 @@ class FileUploadNotificationManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final funElement =
|
final funElement =
|
||||||
message.firstTag('file-upload', xmlns: fileUploadNotificationXmlns)!;
|
message.firstTag('file-upload', xmlns: fileUploadNotificationXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
fun: FileMetadataData.fromXML(
|
..extensions.set(
|
||||||
|
FileUploadNotificationData(
|
||||||
|
FileMetadataData.fromXML(
|
||||||
funElement.firstTag('file', xmlns: fileMetadataXmlns)!,
|
funElement.firstTag('file', xmlns: fileMetadataXmlns)!,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +86,11 @@ class FileUploadNotificationManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final element =
|
final element =
|
||||||
message.firstTag('replaces', xmlns: fileUploadNotificationXmlns)!;
|
message.firstTag('replaces', xmlns: fileUploadNotificationXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
funReplacement: element.attributes['id']! as String,
|
..extensions.set(
|
||||||
|
FileUploadNotificationReplacementData(
|
||||||
|
element.attributes['id']! as String,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +100,11 @@ class FileUploadNotificationManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final element =
|
final element =
|
||||||
message.firstTag('cancels', xmlns: fileUploadNotificationXmlns)!;
|
message.firstTag('cancels', xmlns: fileUploadNotificationXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
funCancellation: element.attributes['id']! as String,
|
..extensions.set(
|
||||||
|
FileUploadNotificationCancellationData(
|
||||||
|
element.attributes['id']! as String,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
await reply(
|
await reply(
|
||||||
@ -195,7 +195,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<StanzaHandlerData> _onDiscoItemsRequest(
|
Future<StanzaHandlerData> _onDiscoItemsRequest(
|
||||||
@ -223,7 +223,7 @@ class DiscoManager extends XmppManagerBase {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
@ -76,7 +76,7 @@ class VCardManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VCardPhoto? _parseVCardPhoto(XMLNode? node) {
|
VCardPhoto? _parseVCardPhoto(XMLNode? node) {
|
||||||
|
@ -114,7 +114,7 @@ class PubSubManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> _getNodeItemCount(JID jid, String node) async {
|
Future<int> _getNodeItemCount(JID jid, String node) async {
|
||||||
|
@ -8,26 +8,24 @@ import 'package:moxxmpp/src/stringxml.dart';
|
|||||||
|
|
||||||
/// A data class representing the jabber:x:oob tag.
|
/// A data class representing the jabber:x:oob tag.
|
||||||
class OOBData {
|
class OOBData {
|
||||||
const OOBData({this.url, this.desc});
|
const OOBData(this.url, this.desc);
|
||||||
|
|
||||||
|
/// The communicated URL of the OOB data
|
||||||
final String? url;
|
final String? url;
|
||||||
|
|
||||||
|
/// The description of the url.
|
||||||
final String? desc;
|
final String? desc;
|
||||||
}
|
|
||||||
|
|
||||||
XMLNode constructOOBNode(OOBData data) {
|
|
||||||
final children = List<XMLNode>.empty(growable: true);
|
|
||||||
|
|
||||||
if (data.url != null) {
|
|
||||||
children.add(XMLNode(tag: 'url', text: data.url));
|
|
||||||
}
|
|
||||||
if (data.desc != null) {
|
|
||||||
children.add(XMLNode(tag: 'desc', text: data.desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
XMLNode toXML() {
|
||||||
return XMLNode.xmlns(
|
return XMLNode.xmlns(
|
||||||
tag: 'x',
|
tag: 'x',
|
||||||
xmlns: oobDataXmlns,
|
xmlns: oobDataXmlns,
|
||||||
children: children,
|
children: [
|
||||||
|
if (url != null) XMLNode(tag: 'url', text: url),
|
||||||
|
if (desc != null) XMLNode(tag: 'desc', text: desc),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OOBManager extends XmppManagerBase {
|
class OOBManager extends XmppManagerBase {
|
||||||
@ -59,10 +57,11 @@ class OOBManager extends XmppManagerBase {
|
|||||||
final url = x.firstTag('url');
|
final url = x.firstTag('url');
|
||||||
final desc = x.firstTag('desc');
|
final desc = x.firstTag('desc');
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
oob: OOBData(
|
..extensions.set(
|
||||||
url: url?.innerText(),
|
OOBData(
|
||||||
desc: desc?.innerText(),
|
url?.innerText(),
|
||||||
|
desc?.innerText(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,39 +6,54 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.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) {
|
factory ChatState.fromString(String state) {
|
||||||
switch (raw) {
|
switch (state) {
|
||||||
case 'active':
|
case 'active':
|
||||||
{
|
|
||||||
return ChatState.active;
|
return ChatState.active;
|
||||||
}
|
|
||||||
case 'composing':
|
case 'composing':
|
||||||
{
|
|
||||||
return ChatState.composing;
|
return ChatState.composing;
|
||||||
}
|
|
||||||
case 'paused':
|
case 'paused':
|
||||||
{
|
|
||||||
return ChatState.paused;
|
return ChatState.paused;
|
||||||
}
|
|
||||||
case 'inactive':
|
case 'inactive':
|
||||||
{
|
|
||||||
return ChatState.inactive;
|
return ChatState.inactive;
|
||||||
}
|
|
||||||
case 'gone':
|
case 'gone':
|
||||||
{
|
|
||||||
return ChatState.gone;
|
return ChatState.gone;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
{
|
|
||||||
return ChatState.gone;
|
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 {
|
class ChatStateManager extends XmppManagerBase {
|
||||||
ChatStateManager() : super(chatStateManager);
|
ChatStateManager() : super(chatStateManager);
|
||||||
|
|
||||||
@ -64,61 +79,27 @@ class ChatStateManager extends XmppManagerBase {
|
|||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
final element = state.stanza.firstTagByXmlns(chatStateXmlns)!;
|
final element = state.stanza.firstTagByXmlns(chatStateXmlns)!;
|
||||||
ChatState? chatState;
|
state.extensions.set(ChatState.fromString(element.tag));
|
||||||
|
return state;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a chat state notification to [to]. You can specify the type attribute
|
/// Send a chat state notification to [to]. You can specify the type attribute
|
||||||
/// of the message with [messageType].
|
/// of the message with [messageType].
|
||||||
void sendChatState(
|
Future<void> sendChatState(
|
||||||
ChatState state,
|
ChatState state,
|
||||||
String to, {
|
String to, {
|
||||||
String messageType = 'chat',
|
String messageType = 'chat',
|
||||||
}) {
|
}) async {
|
||||||
final tagName = state.toString().split('.').last;
|
await getAttributes().sendStanza(
|
||||||
|
|
||||||
getAttributes().sendStanza(
|
|
||||||
StanzaDetails(
|
StanzaDetails(
|
||||||
Stanza.message(
|
Stanza.message(
|
||||||
to: to,
|
to: to,
|
||||||
type: messageType,
|
type: messageType,
|
||||||
children: [
|
children: [
|
||||||
XMLNode.xmlns(tag: tagName, xmlns: chatStateXmlns),
|
XMLNode.xmlns(tag: state.toString(), xmlns: chatStateXmlns),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
awaitable: false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,14 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.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() {
|
XMLNode makeMessageDeliveryRequest() {
|
||||||
return XMLNode.xmlns(
|
return XMLNode.xmlns(
|
||||||
tag: 'request',
|
tag: 'request',
|
||||||
@ -56,7 +64,7 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
|
|||||||
Stanza message,
|
Stanza message,
|
||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
return state.copyWith(deliveryReceiptRequested: true);
|
return state..extensions.set(const MessageDeliveryReceiptData(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<StanzaHandlerData> _onDeliveryReceiptReceived(
|
Future<StanzaHandlerData> _onDeliveryReceiptReceived(
|
||||||
@ -64,16 +72,16 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
|
|||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
final received = message.firstTag('received', xmlns: deliveryXmlns)!;
|
final received = message.firstTag('received', xmlns: deliveryXmlns)!;
|
||||||
for (final item in message.children) {
|
// for (final item in message.children) {
|
||||||
if (!['origin-id', 'stanza-id', 'delay', 'store', 'received']
|
// if (!['origin-id', 'stanza-id', 'delay', 'store', 'received']
|
||||||
.contains(item.tag)) {
|
// .contains(item.tag)) {
|
||||||
logger.info(
|
// logger.info(
|
||||||
"Won't handle stanza as delivery receipt because we found an '${item.tag}' element",
|
// "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(
|
getAttributes().sendEvent(
|
||||||
DeliveryReceiptReceivedEvent(
|
DeliveryReceiptReceivedEvent(
|
||||||
@ -81,6 +89,6 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
|
|||||||
id: received.attributes['id']! as String,
|
id: received.attributes['id']! as String,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<StanzaHandlerData> _unblockPush(
|
Future<StanzaHandlerData> _unblockPush(
|
||||||
@ -92,7 +92,7 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(done: true);
|
return state..done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> block(List<String> items) async {
|
Future<bool> block(List<String> items) async {
|
||||||
|
6
packages/moxxmpp/lib/src/xeps/xep_0198/types.dart
Normal file
6
packages/moxxmpp/lib/src/xeps/xep_0198/types.dart
Normal file
@ -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;
|
||||||
|
}
|
@ -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/negotiator.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0198/nonzas.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/state.dart';
|
||||||
|
import 'package:moxxmpp/src/xeps/xep_0198/types.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
const xmlUintMax = 4294967296; // 2**32
|
const xmlUintMax = 4294967296; // 2**32
|
||||||
@ -402,7 +403,9 @@ class StreamManagementManager extends XmppManagerBase {
|
|||||||
if (isStreamManagementEnabled()) {
|
if (isStreamManagementEnabled()) {
|
||||||
await _incrementC2S();
|
await _incrementC2S();
|
||||||
|
|
||||||
if (state.excludeFromStreamManagement) return state;
|
if (state.extensions.get<StreamManagementData>()?.exclude ?? false) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
_unackedStanzas[_state.c2s] = stanza;
|
_unackedStanzas[_state.c2s] = stanza;
|
||||||
await _sendAckRequest();
|
await _sendAckRequest();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
import 'package:moxxmpp/src/jid.dart';
|
||||||
import 'package:moxxmpp/src/managers/base.dart';
|
import 'package:moxxmpp/src/managers/base.dart';
|
||||||
import 'package:moxxmpp/src/managers/data.dart';
|
import 'package:moxxmpp/src/managers/data.dart';
|
||||||
import 'package:moxxmpp/src/managers/handlers.dart';
|
import 'package:moxxmpp/src/managers/handlers.dart';
|
||||||
@ -7,10 +8,14 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class DelayedDelivery {
|
class DelayedDeliveryData {
|
||||||
const DelayedDelivery(this.from, this.timestamp);
|
const DelayedDeliveryData(this.from, this.timestamp);
|
||||||
|
|
||||||
|
/// The timestamp the message was originally sent.
|
||||||
final DateTime timestamp;
|
final DateTime timestamp;
|
||||||
final String from;
|
|
||||||
|
/// The JID that originally sent the message.
|
||||||
|
final JID from;
|
||||||
}
|
}
|
||||||
|
|
||||||
class DelayedDeliveryManager extends XmppManagerBase {
|
class DelayedDeliveryManager extends XmppManagerBase {
|
||||||
@ -23,6 +28,8 @@ class DelayedDeliveryManager extends XmppManagerBase {
|
|||||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
stanzaTag: 'message',
|
stanzaTag: 'message',
|
||||||
|
tagName: 'delay',
|
||||||
|
tagXmlns: delayedDeliveryXmlns,
|
||||||
callback: _onIncomingMessage,
|
callback: _onIncomingMessage,
|
||||||
priority: 200,
|
priority: 200,
|
||||||
),
|
),
|
||||||
@ -32,12 +39,12 @@ class DelayedDeliveryManager extends XmppManagerBase {
|
|||||||
Stanza stanza,
|
Stanza stanza,
|
||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
final delay = stanza.firstTag('delay', xmlns: delayedDeliveryXmlns);
|
final delay = stanza.firstTag('delay', xmlns: delayedDeliveryXmlns)!;
|
||||||
if (delay == null) return state;
|
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
delayedDelivery: DelayedDelivery(
|
..extensions.set(
|
||||||
delay.attributes['from']! as String,
|
DelayedDeliveryData(
|
||||||
|
JID.fromString(delay.attributes['from']! as String),
|
||||||
DateTime.parse(delay.attributes['stamp']! as String),
|
DateTime.parse(delay.attributes['stamp']! as String),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -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_0297.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0386.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.
|
/// This manager class implements support for XEP-0280.
|
||||||
class CarbonsManager extends XmppManagerBase {
|
class CarbonsManager extends XmppManagerBase {
|
||||||
CarbonsManager() : super(carbonsManager);
|
CarbonsManager() : super(carbonsManager);
|
||||||
@ -77,15 +84,14 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final from = JID.fromString(message.attributes['from']! as String);
|
final from = JID.fromString(message.attributes['from']! as String);
|
||||||
final received = message.firstTag('received', xmlns: carbonsXmlns)!;
|
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 forwarded = received.firstTag('forwarded', xmlns: forwardedXmlns)!;
|
||||||
final carbon = unpackForwarded(forwarded);
|
final carbon = unpackForwarded(forwarded);
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
isCarbon: true,
|
..extensions.set(const CarbonsData(true))
|
||||||
stanza: carbon,
|
..stanza = carbon;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<StanzaHandlerData> _onMessageSent(
|
Future<StanzaHandlerData> _onMessageSent(
|
||||||
@ -94,15 +100,14 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final from = JID.fromString(message.attributes['from']! as String);
|
final from = JID.fromString(message.attributes['from']! as String);
|
||||||
final sent = message.firstTag('sent', xmlns: carbonsXmlns)!;
|
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 forwarded = sent.firstTag('forwarded', xmlns: forwardedXmlns)!;
|
||||||
final carbon = unpackForwarded(forwarded);
|
final carbon = unpackForwarded(forwarded);
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
isCarbon: true,
|
..extensions.set(const CarbonsData(true))
|
||||||
stanza: carbon,
|
..stanza = carbon;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a request to the server, asking it to enable Message Carbons.
|
/// Send a request to the server, asking it to enable Message Carbons.
|
||||||
|
@ -6,14 +6,21 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
|
|
||||||
XMLNode makeLastMessageCorrectionEdit(String id) {
|
class LastMessageCorrectionData {
|
||||||
|
const LastMessageCorrectionData(this.id);
|
||||||
|
|
||||||
|
/// The id the LMC applies to.
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
XMLNode toXML() {
|
||||||
return XMLNode.xmlns(
|
return XMLNode.xmlns(
|
||||||
tag: 'replace',
|
tag: 'replace',
|
||||||
xmlns: lmcXmlns,
|
xmlns: lmcXmlns,
|
||||||
attributes: <String, String>{
|
attributes: {
|
||||||
'id': id,
|
'id': id,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LastMessageCorrectionManager extends XmppManagerBase {
|
class LastMessageCorrectionManager extends XmppManagerBase {
|
||||||
@ -42,8 +49,9 @@ class LastMessageCorrectionManager extends XmppManagerBase {
|
|||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
final edit = stanza.firstTag('replace', xmlns: lmcXmlns)!;
|
final edit = stanza.firstTag('replace', xmlns: lmcXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
lastMessageCorrectionSid: edit.attributes['id']! as String,
|
..extensions.set(
|
||||||
|
LastMessageCorrectionData(edit.attributes['id']! as String),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,13 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.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() {
|
XMLNode makeChatMarkerMarkable() {
|
||||||
return XMLNode.xmlns(
|
return XMLNode.xmlns(
|
||||||
tag: 'markable',
|
tag: 'markable',
|
||||||
@ -54,7 +61,9 @@ class ChatMarkerManager extends XmppManagerBase {
|
|||||||
final marker = message.firstTagByXmlns(chatMarkersXmlns)!;
|
final marker = message.firstTagByXmlns(chatMarkersXmlns)!;
|
||||||
|
|
||||||
// Handle the <markable /> explicitly
|
// Handle the <markable /> 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)) {
|
if (!['received', 'displayed', 'acknowledged'].contains(marker.tag)) {
|
||||||
logger.warning("Unknown message marker '${marker.tag}' found.");
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,10 @@ enum MessageProcessingHint {
|
|||||||
noPermanentStore,
|
noPermanentStore,
|
||||||
noStore,
|
noStore,
|
||||||
noCopies,
|
noCopies,
|
||||||
store,
|
store;
|
||||||
}
|
|
||||||
|
|
||||||
MessageProcessingHint messageProcessingHintFromXml(XMLNode element) {
|
factory MessageProcessingHint.fromName(String name) {
|
||||||
switch (element.tag) {
|
switch (name) {
|
||||||
case 'no-permanent-store':
|
case 'no-permanent-store':
|
||||||
return MessageProcessingHint.noPermanentStore;
|
return MessageProcessingHint.noPermanentStore;
|
||||||
case 'no-store':
|
case 'no-store':
|
||||||
@ -20,12 +19,11 @@ MessageProcessingHint messageProcessingHintFromXml(XMLNode element) {
|
|||||||
return MessageProcessingHint.store;
|
return MessageProcessingHint.store;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false, 'Invalid Message Processing Hint: ${element.tag}');
|
assert(false, 'Invalid Message Processing Hint: $name');
|
||||||
return MessageProcessingHint.noStore;
|
return MessageProcessingHint.noStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension XmlExtension on MessageProcessingHint {
|
XMLNode toXML() {
|
||||||
XMLNode toXml() {
|
|
||||||
String tag;
|
String tag;
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case MessageProcessingHint.noPermanentStore:
|
case MessageProcessingHint.noPermanentStore:
|
||||||
|
@ -7,6 +7,28 @@ import 'package:moxxmpp/src/namespaces.dart';
|
|||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
|
|
||||||
|
class StableIdData {
|
||||||
|
const StableIdData(this.originId, this.stanzaIds);
|
||||||
|
|
||||||
|
/// <origin-id />
|
||||||
|
final String? originId;
|
||||||
|
|
||||||
|
/// Stanza ids
|
||||||
|
final List<StanzaId>? 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 <stanza-id /> element.
|
/// Representation of a <stanza-id /> element.
|
||||||
class StanzaId {
|
class StanzaId {
|
||||||
const 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 {
|
class StableIdManager extends XmppManagerBase {
|
||||||
StableIdManager() : super(stableIdManager);
|
StableIdManager() : super(stableIdManager);
|
||||||
|
|
||||||
@ -86,9 +100,12 @@ class StableIdManager extends XmppManagerBase {
|
|||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
originId: originId,
|
..extensions.set(
|
||||||
stanzaIds: stanzaIds,
|
StableIdData(
|
||||||
|
originId,
|
||||||
|
stanzaIds,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,30 +13,10 @@ enum ExplicitEncryptionType {
|
|||||||
omemo,
|
omemo,
|
||||||
omemo1,
|
omemo1,
|
||||||
omemo2,
|
omemo2,
|
||||||
unknown,
|
unknown;
|
||||||
}
|
|
||||||
|
|
||||||
String _explicitEncryptionTypeToString(ExplicitEncryptionType type) {
|
factory ExplicitEncryptionType.fromNamespace(String namespace) {
|
||||||
switch (type) {
|
switch (namespace) {
|
||||||
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 '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ExplicitEncryptionType _explicitEncryptionTypeFromString(String str) {
|
|
||||||
switch (str) {
|
|
||||||
case emeOtr:
|
case emeOtr:
|
||||||
return ExplicitEncryptionType.otr;
|
return ExplicitEncryptionType.otr;
|
||||||
case emeLegacyOpenPGP:
|
case emeLegacyOpenPGP:
|
||||||
@ -52,18 +32,38 @@ ExplicitEncryptionType _explicitEncryptionTypeFromString(String str) {
|
|||||||
default:
|
default:
|
||||||
return ExplicitEncryptionType.unknown;
|
return ExplicitEncryptionType.unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create an <encryption /> element with [type] indicating which type of encryption was
|
String toNamespace() {
|
||||||
/// used.
|
switch (this) {
|
||||||
XMLNode buildEmeElement(ExplicitEncryptionType 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 '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an <encryption /> element with an xmlns indicating what type of encryption was
|
||||||
|
/// used.
|
||||||
|
XMLNode toXML() {
|
||||||
return XMLNode.xmlns(
|
return XMLNode.xmlns(
|
||||||
tag: 'encryption',
|
tag: 'encryption',
|
||||||
xmlns: emeXmlns,
|
xmlns: emeXmlns,
|
||||||
attributes: <String, String>{
|
attributes: <String, String>{
|
||||||
'namespace': _explicitEncryptionTypeToString(type),
|
'namespace': toNamespace(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EmeManager extends XmppManagerBase {
|
class EmeManager extends XmppManagerBase {
|
||||||
@ -91,8 +91,9 @@ class EmeManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final encryption = message.firstTag('encryption', xmlns: emeXmlns)!;
|
final encryption = message.firstTag('encryption', xmlns: emeXmlns)!;
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
encryptionType: _explicitEncryptionTypeFromString(
|
..extensions.set(
|
||||||
|
ExplicitEncryptionType.fromNamespace(
|
||||||
encryption.attributes['namespace']! as String,
|
encryption.attributes['namespace']! as String,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
|
import 'package:omemo_dart/omemo_dart.dart';
|
||||||
|
|
||||||
/// A simple wrapper class for defining elements that should not be encrypted.
|
/// A simple wrapper class for defining elements that should not be encrypted.
|
||||||
class DoNotEncrypt {
|
class DoNotEncrypt {
|
||||||
const DoNotEncrypt(this.tag, this.xmlns);
|
const DoNotEncrypt(this.tag, this.xmlns);
|
||||||
|
|
||||||
|
/// The tag of the element.
|
||||||
final String tag;
|
final String tag;
|
||||||
|
|
||||||
|
/// The xmlns attribute of the element.
|
||||||
final String xmlns;
|
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<String, OmemoException> jids;
|
||||||
|
final Map<RatchetMapKey, OmemoException> devices;
|
||||||
|
}
|
||||||
|
@ -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_0030/xep_0030.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0060/errors.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_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_0280.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0334.dart';
|
import 'package:moxxmpp/src/xeps/xep_0334.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0380.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
|
// Add a storage hint in case this is a message
|
||||||
// Taken from the example at
|
// Taken from the example at
|
||||||
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
|
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
|
||||||
MessageProcessingHint.store.toXml(),
|
MessageProcessingHint.store.toXML(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
awaitable: false,
|
awaitable: false,
|
||||||
@ -363,18 +364,17 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
|||||||
logger.finest('Encryption done');
|
logger.finest('Encryption done');
|
||||||
|
|
||||||
if (!result.isSuccess(2)) {
|
if (!result.isSuccess(2)) {
|
||||||
final other = Map<String, dynamic>.from(state.other);
|
return state
|
||||||
other['encryption_error_jids'] = result.jidEncryptionErrors;
|
..cancel = true
|
||||||
other['encryption_error_devices'] = result.deviceEncryptionErrors;
|
|
||||||
return state.copyWith(
|
|
||||||
other: other,
|
|
||||||
// If we have no device list for toJid, then the contact most likely does not
|
// If we have no device list for toJid, then the contact most likely does not
|
||||||
// support OMEMO:2
|
// support OMEMO:2
|
||||||
cancelReason: result.jidEncryptionErrors[toJid.toString()]
|
..cancelReason = result.jidEncryptionErrors[toJid.toString()]
|
||||||
is NoKeyMaterialAvailableException
|
is NoKeyMaterialAvailableException
|
||||||
? OmemoNotSupportedForContactException()
|
? OmemoNotSupportedForContactException()
|
||||||
: UnknownOmemoError(),
|
: UnknownOmemoError()
|
||||||
cancel: true,
|
..encryptionError = OmemoEncryptionError(
|
||||||
|
result.jidEncryptionErrors,
|
||||||
|
result.deviceEncryptionErrors,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,19 +389,16 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
|||||||
if (stanza.tag == 'message') {
|
if (stanza.tag == 'message') {
|
||||||
children
|
children
|
||||||
// Add EME data
|
// Add EME data
|
||||||
..add(buildEmeElement(ExplicitEncryptionType.omemo2))
|
..add(ExplicitEncryptionType.omemo2.toXML())
|
||||||
// Add a storage hint in case this is a message
|
// Add a storage hint in case this is a message
|
||||||
// Taken from the example at
|
// Taken from the example at
|
||||||
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
|
// https://xmpp.org/extensions/xep-0384.html#message-structure-description.
|
||||||
..add(MessageProcessingHint.store.toXml());
|
..add(MessageProcessingHint.store.toXML());
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
stanza: state.stanza.copyWith(
|
..stanza = state.stanza.copyWith(children: children)
|
||||||
children: children,
|
..encrypted = true;
|
||||||
),
|
|
||||||
encrypted: true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function is called whenever a message is to be encrypted. If it returns 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(
|
OmemoIncomingStanza(
|
||||||
fromJid.toString(),
|
fromJid.toString(),
|
||||||
sid,
|
sid,
|
||||||
state.delayedDelivery?.timestamp.millisecondsSinceEpoch ??
|
state.extensions
|
||||||
|
.get<DelayedDeliveryData>()
|
||||||
|
?.timestamp
|
||||||
|
.millisecondsSinceEpoch ??
|
||||||
DateTime.now().millisecondsSinceEpoch,
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
keys,
|
keys,
|
||||||
payloadElement?.innerText(),
|
payloadElement?.innerText(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final other = Map<String, dynamic>.from(state.other);
|
|
||||||
var children = stanza.children;
|
var children = stanza.children;
|
||||||
if (result.error != null) {
|
if (result.error != null) {
|
||||||
other['encryption_error'] = result.error;
|
state.encryptionError = result.error;
|
||||||
} else {
|
} else {
|
||||||
children = stanza.children
|
children = stanza.children
|
||||||
.where(
|
.where(
|
||||||
@ -471,11 +470,9 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
|||||||
envelope = XMLNode.fromString(result.payload!);
|
envelope = XMLNode.fromString(result.payload!);
|
||||||
} on XmlParserException catch (_) {
|
} on XmlParserException catch (_) {
|
||||||
logger.warning('Failed to parse envelope payload: ${result.payload!}');
|
logger.warning('Failed to parse envelope payload: ${result.payload!}');
|
||||||
other['encryption_error'] = InvalidEnvelopePayloadException();
|
return state
|
||||||
return state.copyWith(
|
..encrypted = true
|
||||||
encrypted: true,
|
..encryptionError = InvalidEnvelopePayloadException();
|
||||||
other: other,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final envelopeChildren = envelope.firstTag('content')?.children;
|
final envelopeChildren = envelope.firstTag('content')?.children;
|
||||||
@ -489,13 +486,13 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!checkAffixElements(envelope, stanza.from!, ourJid)) {
|
if (!checkAffixElements(envelope, stanza.from!, ourJid)) {
|
||||||
other['encryption_error'] = InvalidAffixElementsException();
|
state.encryptionError = InvalidAffixElementsException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
encrypted: true,
|
..encrypted = true
|
||||||
stanza: Stanza(
|
..stanza = Stanza(
|
||||||
to: stanza.to,
|
to: stanza.to,
|
||||||
from: stanza.from,
|
from: stanza.from,
|
||||||
id: stanza.id,
|
id: stanza.id,
|
||||||
@ -503,8 +500,6 @@ abstract class BaseOmemoManager extends XmppManagerBase {
|
|||||||
children: children,
|
children: children,
|
||||||
tag: stanza.tag,
|
tag: stanza.tag,
|
||||||
attributes: Map<String, String>.from(stanza.attributes),
|
attributes: Map<String, String>.from(stanza.attributes),
|
||||||
),
|
|
||||||
other: other,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class SIMSManager extends XmppManagerBase {
|
|||||||
final references = message.findTags('reference', xmlns: referenceXmlns);
|
final references = message.findTags('reference', xmlns: referenceXmlns);
|
||||||
for (final ref in references) {
|
for (final ref in references) {
|
||||||
final sims = ref.firstTag('media-sharing', xmlns: simsXmlns);
|
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;
|
return state;
|
||||||
|
@ -47,8 +47,9 @@ class MessageRetractionManager extends XmppManagerBase {
|
|||||||
final isFallbackBody =
|
final isFallbackBody =
|
||||||
message.firstTag('fallback', xmlns: fallbackIndicationXmlns) != null;
|
message.firstTag('fallback', xmlns: fallbackIndicationXmlns) != null;
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
messageRetraction: MessageRetractionData(
|
..extensions.set(
|
||||||
|
MessageRetractionData(
|
||||||
applyTo.attributes['id']! as String,
|
applyTo.attributes['id']! as String,
|
||||||
isFallbackBody ? message.firstTag('body')?.innerText() : null,
|
isFallbackBody ? message.firstTag('body')?.innerText() : null,
|
||||||
),
|
),
|
||||||
|
@ -55,8 +55,9 @@ class MessageReactionsManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final reactionsElement =
|
final reactionsElement =
|
||||||
message.firstTag('reactions', xmlns: messageReactionsXmlns)!;
|
message.firstTag('reactions', xmlns: messageReactionsXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
messageReactions: MessageReactions(
|
..extensions.set(
|
||||||
|
MessageReactions(
|
||||||
reactionsElement.attributes['id']! as String,
|
reactionsElement.attributes['id']! as String,
|
||||||
reactionsElement.children
|
reactionsElement.children
|
||||||
.where((c) => c.tag == 'reaction')
|
.where((c) => c.tag == 'reaction')
|
||||||
|
@ -135,10 +135,9 @@ class SFSManager extends XmppManagerBase {
|
|||||||
) async {
|
) async {
|
||||||
final sfs = message.firstTag('file-sharing', xmlns: sfsXmlns)!;
|
final sfs = message.firstTag('file-sharing', xmlns: sfsXmlns)!;
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
sfs: StatelessFileSharingData.fromXML(
|
..extensions.set(
|
||||||
sfs,
|
StatelessFileSharingData.fromXML(sfs),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
class StickersManager extends XmppManagerBase {
|
||||||
StickersManager() : super(stickersManager);
|
StickersManager() : super(stickersManager);
|
||||||
|
|
||||||
@ -249,8 +256,9 @@ class StickersManager extends XmppManagerBase {
|
|||||||
StanzaHandlerData state,
|
StanzaHandlerData state,
|
||||||
) async {
|
) async {
|
||||||
final sticker = stanza.firstTag('sticker', xmlns: stickersXmlns)!;
|
final sticker = stanza.firstTag('sticker', xmlns: stickersXmlns)!;
|
||||||
return state.copyWith(
|
return state
|
||||||
stickerPackId: sticker.attributes['pack']! as String,
|
..extensions.set(
|
||||||
|
StickersData(sticker.attributes['pack']! as String),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,8 +103,9 @@ class MessageRepliesManager extends XmppManagerBase {
|
|||||||
end = int.parse(body.attributes['end']! as String);
|
end = int.parse(body.attributes['end']! as String);
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.copyWith(
|
return state
|
||||||
reply: ReplyData(
|
..extensions.set(
|
||||||
|
ReplyData(
|
||||||
id: id,
|
id: id,
|
||||||
to: to,
|
to: to,
|
||||||
start: start,
|
start: start,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
|
import 'package:moxxmpp/src/util/typed_map.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
final stanza1 = Stanza.iq(
|
final stanza1 = Stanza.iq(
|
||||||
@ -16,8 +17,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -38,8 +39,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagXmlns: 'owo',
|
tagXmlns: 'owo',
|
||||||
);
|
);
|
||||||
@ -59,8 +60,8 @@ void main() {
|
|||||||
return StanzaHandlerData(
|
return StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
stanzaTag: 'iq',
|
stanzaTag: 'iq',
|
||||||
@ -77,8 +78,8 @@ void main() {
|
|||||||
StanzaHandlerData(
|
StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza2,
|
stanza2,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(run, true);
|
expect(run, true);
|
||||||
@ -89,8 +90,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagName: 'tag',
|
tagName: 'tag',
|
||||||
);
|
);
|
||||||
@ -107,8 +108,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagName: 'tag',
|
tagName: 'tag',
|
||||||
stanzaTag: 'iq',
|
stanzaTag: 'iq',
|
||||||
@ -127,8 +128,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
xmlns: componentAcceptXmlns,
|
xmlns: componentAcceptXmlns,
|
||||||
);
|
);
|
||||||
@ -147,8 +148,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagName: '1',
|
tagName: '1',
|
||||||
priority: 100,
|
priority: 100,
|
||||||
@ -157,8 +158,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagName: '2',
|
tagName: '2',
|
||||||
),
|
),
|
||||||
@ -166,8 +167,8 @@ void main() {
|
|||||||
callback: (stanza, _) async => StanzaHandlerData(
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
tagName: '3',
|
tagName: '3',
|
||||||
priority: 50,
|
priority: 50,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
|
import 'package:moxxmpp/src/util/typed_map.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import '../helpers/logging.dart';
|
import '../helpers/logging.dart';
|
||||||
import '../helpers/xmpp.dart';
|
import '../helpers/xmpp.dart';
|
||||||
@ -15,8 +16,8 @@ Future<void> runIncomingStanzaHandlers(
|
|||||||
StanzaHandlerData(
|
StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -34,8 +35,8 @@ Future<void> runOutgoingStanzaHandlers(
|
|||||||
StanzaHandlerData(
|
StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
|
import 'package:moxxmpp/src/util/typed_map.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'helpers/logging.dart';
|
import 'helpers/logging.dart';
|
||||||
import 'helpers/xmpp.dart';
|
import 'helpers/xmpp.dart';
|
||||||
@ -78,8 +79,8 @@ Future<bool> testRosterManager(
|
|||||||
StanzaHandlerData(
|
StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
stanza,
|
stanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -335,8 +336,8 @@ void main() {
|
|||||||
StanzaHandlerData(
|
StanzaHandlerData(
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
null,
|
|
||||||
maliciousStanza,
|
maliciousStanza,
|
||||||
|
TypedMap(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user