xmpp: Rework the stanza handler
This commit is contained in:
parent
648b83fc08
commit
ae643e7009
@ -5,7 +5,7 @@ import "package:moxxyv2/xmpp/roster.dart";
|
||||
|
||||
import "package:get_it/get_it.dart";
|
||||
|
||||
class MoxxyRosterManger extends RosterManager {
|
||||
class MoxxyRosterManager extends RosterManager {
|
||||
@override
|
||||
Future<void> commitLastRosterVersion(String version) async {
|
||||
await GetIt.I.get<XmppService>().modifyXmppState((state) => state.copyWith(
|
||||
|
@ -11,10 +11,16 @@ import "package:moxxyv2/xmpp/presence.dart";
|
||||
import "package:moxxyv2/xmpp/message.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0054.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0280.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0352.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0060.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0066.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0084.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0184.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0280.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0333.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0352.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0359.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0385.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0447.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/cachemanager.dart";
|
||||
import "package:moxxyv2/service/managers/roster.dart";
|
||||
import "package:moxxyv2/service/managers/disco.dart";
|
||||
@ -209,17 +215,25 @@ void onStart() {
|
||||
GetIt.I.registerSingleton<RosterService>(RosterService(sendData: middleware));
|
||||
|
||||
final connection = XmppConnection();
|
||||
connection.registerManager(MoxxyStreamManagementManager());
|
||||
connection.registerManager(MoxxyDiscoManager());
|
||||
connection.registerManager(MessageManager());
|
||||
connection.registerManager(MoxxyRosterManger());
|
||||
connection.registerManager(PresenceManager());
|
||||
connection.registerManager(CSIManager());
|
||||
connection.registerManager(DiscoCacheManager());
|
||||
connection.registerManager(CarbonsManager());
|
||||
connection.registerManager(PubSubManager());
|
||||
connection.registerManager(vCardManager());
|
||||
connection.registerManager(UserAvatarManager());
|
||||
connection.registerManagers([
|
||||
MoxxyStreamManagementManager(),
|
||||
MoxxyDiscoManager(),
|
||||
MoxxyRosterManager(),
|
||||
MessageManager(),
|
||||
PresenceManager(),
|
||||
CSIManager(),
|
||||
DiscoCacheManager(),
|
||||
CarbonsManager(),
|
||||
PubSubManager(),
|
||||
vCardManager(),
|
||||
UserAvatarManager(),
|
||||
StableIdManager(),
|
||||
SIMSManager(),
|
||||
MessageDeliveryReceiptManager(),
|
||||
ChatMarkerManager(),
|
||||
OOBManager(),
|
||||
SFSManager()
|
||||
]);
|
||||
GetIt.I.registerSingleton<XmppConnection>(connection);
|
||||
|
||||
final account = await xmpp.getAccountData();
|
||||
|
@ -15,7 +15,9 @@ import "package:moxxyv2/xmpp/roster.dart";
|
||||
import "package:moxxyv2/xmpp/sasl/authenticator.dart";
|
||||
import "package:moxxyv2/xmpp/sasl/authenticators.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/attributes.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/xep_0030.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/cachemanager.dart";
|
||||
@ -56,33 +58,46 @@ class StartTLSNonza extends XMLNode {
|
||||
}
|
||||
|
||||
class XmppConnection {
|
||||
late ConnectionSettings _connectionSettings;
|
||||
final StreamController<XmppEvent> _eventStreamController;
|
||||
final Map<String, Completer<XMLNode>> _awaitingResponse;
|
||||
final Map<String, XmppManagerBase> _xmppManagers;
|
||||
final List<StanzaHandler> _incomingStanzaHandlers;
|
||||
final List<StanzaHandler> _outgoingStanzaHandlers;
|
||||
final BaseSocketWrapper _socket;
|
||||
XmppConnectionState _connectionState;
|
||||
late final Stream<String> _socketStream;
|
||||
final StreamController<XmppEvent> _eventStreamController;
|
||||
final Map<String, Completer<XMLNode>> _awaitingResponse = {};
|
||||
final Map<String, XmppManagerBase> _xmppManagers = {};
|
||||
late ConnectionSettings _connectionSettings;
|
||||
|
||||
// Stream properties
|
||||
//
|
||||
// Stream feature XMLNS
|
||||
/// Stream properties
|
||||
///
|
||||
/// Features we got after SASL auth (xmlns)
|
||||
final List<String> _streamFeatures = List.empty(growable: true);
|
||||
/// Disco info we got after binding a resource (xmlns)
|
||||
final List<String> _serverFeatures = List.empty(growable: true);
|
||||
RoutingState _routingState;
|
||||
String _resource;
|
||||
/// The buffer object to keep split up stanzas together
|
||||
final XmlStreamBuffer _streamBuffer;
|
||||
Timer? _connectionPingTimer;
|
||||
int _currentBackoffAttempt;
|
||||
Timer? _backoffTimer;
|
||||
/// UUID object to generate stanza and origin IDs
|
||||
final Uuid _uuid;
|
||||
bool _resuming; // For indicating in a [ConnectionStateChangedEvent] that the event occured because we did a reconnection
|
||||
/// The time between sending a ping to keep the connection open
|
||||
// TODO: Only start the timer if we did not send a stanza after n seconds
|
||||
final Duration connectionPingDuration;
|
||||
/// The current state of the connection handling state machine.
|
||||
RoutingState _routingState;
|
||||
/// The currently bound resource or "" if none has been bound yet.
|
||||
String _resource;
|
||||
/// Counter for how manyy we have tried to reconnect.
|
||||
int _currentBackoffAttempt;
|
||||
/// For indicating in a [ConnectionStateChangedEvent] that the event occured because we
|
||||
/// did a reconnection.
|
||||
bool _resuming;
|
||||
/// Timers for the keep-alive ping and the backoff connection process.
|
||||
Timer? _connectionPingTimer;
|
||||
Timer? _backoffTimer;
|
||||
|
||||
// Negotiators
|
||||
/// Negotiators
|
||||
late AuthenticationNegotiator _authenticator;
|
||||
|
||||
// Misc
|
||||
/// Misc
|
||||
final Logger _log;
|
||||
|
||||
/// [socket] is for debugging purposes.
|
||||
@ -102,6 +117,10 @@ class XmppConnection {
|
||||
_uuid = const Uuid(),
|
||||
// NOTE: For testing
|
||||
_socket = socket ?? TCPSocketWrapper(),
|
||||
_awaitingResponse = {},
|
||||
_xmppManagers = {},
|
||||
_incomingStanzaHandlers = List.empty(growable: true),
|
||||
_outgoingStanzaHandlers = List.empty(growable: true),
|
||||
_log = Logger("XmppConnection") {
|
||||
_socketStream = _socket.getDataStream();
|
||||
// TODO: Handle on done
|
||||
@ -109,8 +128,11 @@ class XmppConnection {
|
||||
_socket.getErrorStream().listen(_handleError);
|
||||
}
|
||||
|
||||
/// Registers an [XmppManagerBase] subclass as a manager on this connection
|
||||
void registerManager(XmppManagerBase manager) {
|
||||
/// Registers an [XmppManagerBase] sub-class as a manager on this connection.
|
||||
/// [sortHandlers] should NOT be touched. It specified if the handler priorities
|
||||
/// should be set up. The only time this should be false is when called via
|
||||
/// [registerManagers].
|
||||
void registerManager(XmppManagerBase manager, { bool sortHandlers = true }) {
|
||||
_log.finest("Registering ${manager.getId()}");
|
||||
manager.register(XmppManagerAttributes(
|
||||
sendStanza: sendStanza,
|
||||
@ -136,8 +158,27 @@ class XmppConnection {
|
||||
} else if (_xmppManagers.containsKey(discoManager)) {
|
||||
(_xmppManagers[discoManager] as DiscoManager).addDiscoFeatures(manager.getDiscoFeatures());
|
||||
}
|
||||
|
||||
_incomingStanzaHandlers.addAll(manager.getIncomingStanzaHandlers());
|
||||
_outgoingStanzaHandlers.addAll(manager.getOutgoingStanzaHandlers());
|
||||
|
||||
if (sortHandlers) {
|
||||
_incomingStanzaHandlers.sort(stanzaHandlerSortComparator);
|
||||
_outgoingStanzaHandlers.sort(stanzaHandlerSortComparator);
|
||||
}
|
||||
}
|
||||
|
||||
/// Like [registerManager], but for a list of managers.
|
||||
void registerManagers(List<XmppManagerBase> managers) {
|
||||
for (final manager in managers) {
|
||||
registerManager(manager, sortHandlers: false);
|
||||
}
|
||||
|
||||
// Sort them
|
||||
_incomingStanzaHandlers.sort(stanzaHandlerSortComparator);
|
||||
_outgoingStanzaHandlers.sort(stanzaHandlerSortComparator);
|
||||
}
|
||||
|
||||
/// Generate an Id suitable for an origin-id or stanza id
|
||||
String generateId() {
|
||||
return _uuid.v4();
|
||||
@ -256,7 +297,7 @@ class XmppConnection {
|
||||
/// [stanza] has none.
|
||||
/// If addId is true, then an "id" attribute will be added to the stanza if [stanza] has
|
||||
/// none.
|
||||
Future<XMLNode> sendStanza(Stanza stanza, { bool addFrom = true, bool addId = true, bool awaitable = true }) {
|
||||
Future<XMLNode> sendStanza(Stanza stanza, { bool addFrom = true, bool addId = true, bool awaitable = true }) async {
|
||||
// Add extra data in case it was not set
|
||||
if (addId && (stanza.id == null || stanza.id == "")) {
|
||||
stanza = stanza.copyWith(id: generateId());
|
||||
@ -271,6 +312,9 @@ class XmppConnection {
|
||||
_awaitingResponse[stanza.id!] = Completer();
|
||||
}
|
||||
|
||||
// Tell the SM manager that we're about to send a stanza
|
||||
await _runOutoingStanzaHandlers(stanza);
|
||||
|
||||
// This uses the StreamManager to behave like a send queue
|
||||
if (_canSendData()) {
|
||||
_socket.write(stanzaString);
|
||||
@ -279,9 +323,6 @@ class XmppConnection {
|
||||
// NOTE: Here we have send an Ack request nonza. This is now done by StreamManagementManager when receiving the StanzaSentEvent
|
||||
}
|
||||
|
||||
// Tell the SM manager that we're about to send a stanza
|
||||
_sendEvent(StanzaSentEvent(stanza: stanza));
|
||||
|
||||
if (awaitable) {
|
||||
return _awaitingResponse[stanza.id!]!.future;
|
||||
} else {
|
||||
@ -385,6 +426,34 @@ class XmppConnection {
|
||||
_log.warning("Failed to discover server items using XEP-0030");
|
||||
}
|
||||
}
|
||||
|
||||
/// Iterate over [handlers] and check if the handler matches [stanza]. If it does,
|
||||
/// call its callback and end the processing if the callback returned true; continue
|
||||
/// if it returned false.
|
||||
Future<bool> _runStanzaHandlers(List<StanzaHandler> handlers, Stanza stanza) async {
|
||||
StanzaHandlerData state = StanzaHandlerData(false, stanza);
|
||||
for (final handler in handlers) {
|
||||
if (handler.matches(stanza)) {
|
||||
state = await handler.callback(stanza, state);
|
||||
if (state.done) return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> _runIncomingStanzaHandlers(Stanza stanza) async {
|
||||
return await _runStanzaHandlers(
|
||||
_incomingStanzaHandlers,
|
||||
stanza
|
||||
);
|
||||
}
|
||||
Future<bool> _runOutoingStanzaHandlers(Stanza stanza) async {
|
||||
return await _runStanzaHandlers(
|
||||
_outgoingStanzaHandlers,
|
||||
stanza
|
||||
);
|
||||
}
|
||||
|
||||
/// Called whenever we receive a stanza after resource binding or stream resumption.
|
||||
Future<void> _handleStanza(XMLNode nonza) async {
|
||||
@ -413,16 +482,8 @@ class XmppConnection {
|
||||
_awaitingResponse.remove(id);
|
||||
return;
|
||||
}
|
||||
|
||||
bool stanzaHandled = false;
|
||||
await Future.forEach(
|
||||
_xmppManagers.values,
|
||||
(XmppManagerBase manager) async {
|
||||
final handled = await manager.runStanzaHandlers(stanza);
|
||||
|
||||
if (!stanzaHandled && handled) stanzaHandled = true;
|
||||
}
|
||||
);
|
||||
final stanzaHandled = await _runIncomingStanzaHandlers(stanza);
|
||||
|
||||
if (!stanzaHandled) {
|
||||
handleUnhandledStanza(this, stanza);
|
||||
|
@ -33,13 +33,6 @@ class AuthenticationFailedEvent extends XmppEvent {
|
||||
AuthenticationFailedEvent({ required this.saslError });
|
||||
}
|
||||
|
||||
/// Triggered when we send a stanza to the socket
|
||||
class StanzaSentEvent extends XmppEvent {
|
||||
final Stanza stanza;
|
||||
|
||||
StanzaSentEvent({ required this.stanza });
|
||||
}
|
||||
|
||||
/// Triggered when we want to ping the connection open
|
||||
class SendPingEvent extends XmppEvent {}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/attributes.dart";
|
||||
|
||||
@ -22,9 +21,14 @@ abstract class XmppManagerBase {
|
||||
return _managerAttributes;
|
||||
}
|
||||
|
||||
/// Return the [StanzaHandler]s associated with this manager.
|
||||
List<StanzaHandler> getStanzaHandlers() => [];
|
||||
/// Return the [StanzaHandler]s associated with this manager that deal with stanzas we
|
||||
/// send.
|
||||
List<StanzaHandler> getOutgoingStanzaHandlers() => [];
|
||||
|
||||
/// Return the [StanzaHandler]s associated with this manager that deal with stanzas we
|
||||
/// receive.
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [];
|
||||
|
||||
/// Return the [NonzaHandler]s associated with this manager.
|
||||
List<NonzaHandler> getNonzaHandlers() => [];
|
||||
|
||||
@ -59,21 +63,4 @@ abstract class XmppManagerBase {
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
/// Runs all [StanzaHandlers] of this Manager which match the nonza. Resolves to true if
|
||||
/// the nonza has been handled by one of the handlers. Resolves to false otherwise.
|
||||
Future<bool> runStanzaHandlers(Stanza stanza) async {
|
||||
bool handled = false;
|
||||
await Future.forEach(
|
||||
getStanzaHandlers(),
|
||||
(StanzaHandler handler) async {
|
||||
if (handler.matches(stanza)) {
|
||||
handled = true;
|
||||
await handler.callback(stanza);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return handled;
|
||||
}
|
||||
}
|
||||
|
29
lib/xmpp/managers/data.dart
Normal file
29
lib/xmpp/managers/data.dart
Normal file
@ -0,0 +1,29 @@
|
||||
import "package:freezed_annotation/freezed_annotation.dart";
|
||||
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0066.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0359.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0385.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0447.dart";
|
||||
|
||||
part "data.freezed.dart";
|
||||
|
||||
@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,
|
||||
// The stanza that is being dealt with
|
||||
Stanza stanza,
|
||||
{
|
||||
StatelessMediaSharingData? sims,
|
||||
StatelessFileSharingData? sfs,
|
||||
OOBData? oob,
|
||||
StableStanzaId? stableId,
|
||||
@Default(false) bool isCarbon,
|
||||
@Default(false) bool deliveryReceiptRequested,
|
||||
@Default(false) bool isMarkable
|
||||
}
|
||||
) = _StanzaHandlerData;
|
||||
}
|
@ -2,16 +2,16 @@ import "package:moxxyv2/shared/helpers.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
|
||||
class NonzaHandler {
|
||||
abstract class Handler {
|
||||
final String? nonzaTag;
|
||||
final String? nonzaXmlns;
|
||||
final bool matchStanzas;
|
||||
final Future<bool> Function(XMLNode) callback;
|
||||
|
||||
NonzaHandler({ this.nonzaTag, this.nonzaXmlns, required this.callback, this.matchStanzas = false });
|
||||
const Handler(this.matchStanzas, { this.nonzaTag, this.nonzaXmlns });
|
||||
|
||||
/// Returns true if the node matches the description provided by this NonzaHandler
|
||||
/// Returns true if the node matches the description provided by this [Handler].
|
||||
bool matches(XMLNode node) {
|
||||
bool matches = false;
|
||||
|
||||
@ -31,17 +31,38 @@ class NonzaHandler {
|
||||
}
|
||||
}
|
||||
|
||||
class StanzaHandler extends NonzaHandler {
|
||||
final String? tagXmlns;
|
||||
class NonzaHandler extends Handler {
|
||||
final Future<bool> Function(XMLNode) callback;
|
||||
|
||||
NonzaHandler({
|
||||
required this.callback,
|
||||
String? nonzaTag,
|
||||
String? nonzaXmlns
|
||||
}) : super(
|
||||
false,
|
||||
nonzaTag: nonzaTag,
|
||||
nonzaXmlns: nonzaXmlns
|
||||
);
|
||||
}
|
||||
|
||||
class StanzaHandler extends Handler {
|
||||
final String? tagName;
|
||||
final String? tagXmlns;
|
||||
final int priority;
|
||||
final Future<StanzaHandlerData> Function(Stanza, StanzaHandlerData) callback;
|
||||
|
||||
StanzaHandler({ this.tagXmlns, this.tagName, String? stanzaTag, required Future<bool> Function(Stanza) callback }) : super(
|
||||
matchStanzas: true,
|
||||
StanzaHandler({
|
||||
required this.callback,
|
||||
this.tagXmlns,
|
||||
this.tagName,
|
||||
this.priority = 0,
|
||||
String? stanzaTag,
|
||||
}) : super(
|
||||
true,
|
||||
nonzaTag: stanzaTag,
|
||||
nonzaXmlns: stanzaXmlns,
|
||||
callback: (XMLNode node) async => await callback(Stanza.fromXMLNode(node))
|
||||
nonzaXmlns: stanzaXmlns
|
||||
);
|
||||
|
||||
|
||||
@override
|
||||
bool matches(XMLNode node) {
|
||||
bool matches = super.matches(node);
|
||||
@ -68,3 +89,5 @@ class StanzaHandler extends NonzaHandler {
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
|
||||
int stanzaHandlerSortComparator(StanzaHandler a, StanzaHandler b) => b.priority.compareTo(a.priority);
|
||||
|
@ -9,3 +9,9 @@ const carbonsManager = "im.moxxy.carbonsmanager";
|
||||
const vcardManager = "im.moxxy.vcardmanager";
|
||||
const pubsubManager = "im.moxxy.pubsubmanager";
|
||||
const userAvatarManager = "im.moxxy.useravatarmanager";
|
||||
const stableIdManager = "im.moxxy.stableidmanager";
|
||||
const simsManager = "im.moxxy.simsmanager";
|
||||
const messageDeliveryReceiptManager = "im.moxxy.messagedeliveryreceiptmanager";
|
||||
const chatMarkerManager = "im.moxxy.chatmarkermanager";
|
||||
const oobManager = "im.moxxy.oobmanager";
|
||||
const sfsManager = "im.moxxy.sfsmanager";
|
||||
|
0
lib/xmpp/managers/priorities.dart
Normal file
0
lib/xmpp/managers/priorities.dart
Normal file
@ -4,17 +4,12 @@ import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/cachemanager.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0066.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0184.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0280.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0297.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0333.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0359.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0385.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0447.dart";
|
||||
|
||||
class MessageDetails {
|
||||
final String to;
|
||||
@ -48,162 +43,34 @@ class MessageManager extends XmppManagerBase {
|
||||
String getName() => "MessageManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
callback: _onMessage
|
||||
callback: _onMessage,
|
||||
priority: -100
|
||||
)
|
||||
];
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ chatMarkersXmlns, oobDataXmlns, deliveryXmlns, stableIdXmlns ];
|
||||
|
||||
/// Helper function to extract and verify the origin and stanza Id according to
|
||||
/// XEP-0359.
|
||||
/// Requires a [DiscoCacheManager] to be registered in order to provide anything
|
||||
/// other than [null].
|
||||
Future<StableStanzaId> _getStanzaId(Stanza message) async {
|
||||
final from = JID.fromString(message.attributes["from"]!);
|
||||
String? originId;
|
||||
String? stanzaId;
|
||||
String? stanzaIdBy;
|
||||
final originIdTag = message.firstTag("origin-id", xmlns: stableIdXmlns);
|
||||
final stanzaIdTag = message.firstTag("stanza-id", xmlns: stableIdXmlns);
|
||||
if (originIdTag != null || stanzaIdTag != null) {
|
||||
logger.finest("Found Unique and Stable Stanza Id tag");
|
||||
final attrs = getAttributes();
|
||||
final cache = attrs.getManagerById(discoCacheManager) as DiscoCacheManager?;
|
||||
if (cache != null) {
|
||||
final info = await cache.getInfoByJid(from.toString());
|
||||
if (info != null) {
|
||||
logger.finest("Got info for ${from.toString()}");
|
||||
if (info.features.contains(stableIdXmlns)) {
|
||||
logger.finest("${from.toString()} supports $stableIdXmlns.");
|
||||
|
||||
if (originIdTag != null) {
|
||||
originId = originIdTag.attributes["id"]!;
|
||||
}
|
||||
|
||||
if (stanzaIdTag != null) {
|
||||
stanzaId = stanzaIdTag.attributes["id"]!;
|
||||
stanzaIdBy = stanzaIdTag.attributes["by"]!;
|
||||
}
|
||||
} else {
|
||||
logger.finest("${from.toString()} does not support $stableIdXmlns. Ignoring... ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StableStanzaId(
|
||||
originId: originId,
|
||||
stanzaId: stanzaId,
|
||||
stanzaIdBy: stanzaIdBy
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleChatMarker(Stanza message, XMLNode marker) async {
|
||||
final attrs = getAttributes();
|
||||
|
||||
if (!["received", "displayed", "acknowledged"].contains(marker.tag)) {
|
||||
logger.warning("Unknown message marker '${marker.tag}' found.");
|
||||
return;
|
||||
}
|
||||
|
||||
attrs.sendEvent(ChatMarkerEvent(
|
||||
from: JID.fromString(message.from!),
|
||||
type: marker.tag,
|
||||
id: marker.attributes["id"]!,
|
||||
));
|
||||
}
|
||||
StatelessMediaSharingData? _getSIMS(Stanza message) {
|
||||
final references = message.findTags("reference", xmlns: referenceXmlns);
|
||||
for (final ref in references) {
|
||||
final sims = ref.firstTag("media-sharing", xmlns: simsXmlns);
|
||||
if (sims != null) return parseSIMSElement(sims);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _isDeliveryReceiptResponse(Stanza message) {
|
||||
final received = message.firstTag("received", xmlns: deliveryXmlns);
|
||||
if (received == null) return null;
|
||||
|
||||
for (final item in message.children) {
|
||||
if (!["origin-id", "stanza-id", "delay"].contains(item.tag)) {
|
||||
logger.info("Won't handle stanza as delivery receipt because we found an '${item.tag}' element");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return received.attributes["id"]!;
|
||||
}
|
||||
|
||||
Future<bool> _onMessage(Stanza message) async {
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
// First check if it's a carbon
|
||||
final from = JID.fromString(message.attributes["from"]!);
|
||||
final received = message.firstTag("received", xmlns: carbonsXmlns);
|
||||
final attrs = getAttributes();
|
||||
bool isCarbon = false;
|
||||
if (received != null) {
|
||||
final cm = attrs.getManagerById(carbonsManager) as CarbonsManager?;
|
||||
|
||||
// Ignore invalid carbons
|
||||
if (cm == null || !cm.isCarbonValid(from)) return true;
|
||||
|
||||
final forwarded = received.firstTag("forwarded", xmlns: forwardedXmlns)!;
|
||||
message = unpackForwarded(forwarded);
|
||||
isCarbon = true;
|
||||
}
|
||||
|
||||
final did = _isDeliveryReceiptResponse(message);
|
||||
if (did != null) {
|
||||
attrs.sendEvent(DeliveryReceiptReceivedEvent(from: from, id: did));
|
||||
return true;
|
||||
}
|
||||
|
||||
final sfs = message.firstTag("file-sharing", xmlns: sfsXmlns);
|
||||
final sims = _getSIMS(message);
|
||||
final body = message.firstTag("body");
|
||||
if (body == null && sfs == null && sims == null) {
|
||||
final marker = message.firstTagByXmlns(chatMarkersXmlns);
|
||||
if (marker != null) {
|
||||
// Response to a marker
|
||||
await _handleChatMarker(message, marker);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
OOBData? oob;
|
||||
final oobTag = message.firstTag("x", xmlns: oobDataXmlns);
|
||||
if (oobTag != null) {
|
||||
final url = oobTag.firstTag("url");
|
||||
final desc = oobTag.firstTag("desc");
|
||||
oob = OOBData(
|
||||
url: url?.innerText(),
|
||||
desc: desc?.innerText()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
getAttributes().sendEvent(MessageEvent(
|
||||
body: body != null ? body.innerText() : "",
|
||||
fromJid: from,
|
||||
sid: message.attributes["id"]!,
|
||||
stanzaId: state.stableId ?? StableStanzaId(),
|
||||
isCarbon: state.isCarbon,
|
||||
deliveryReceiptRequested: state.deliveryReceiptRequested,
|
||||
isMarkable: state.isMarkable,
|
||||
type: message.attributes["type"],
|
||||
stanzaId: await _getStanzaId(message),
|
||||
isMarkable: message.firstTag("markable", xmlns: chatMarkersXmlns) != null,
|
||||
isCarbon: isCarbon,
|
||||
deliveryReceiptRequested: message.firstTag("request", xmlns: deliveryXmlns) != null,
|
||||
oob: oob,
|
||||
sfs: sfs != null ? parseSFSElement(sfs) : null,
|
||||
sims: sims
|
||||
oob: state.oob,
|
||||
sfs: state.sfs,
|
||||
sims: state.sims
|
||||
));
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
/// Send a message to [to] with the content [body]. If [deliveryRequest] is true, then
|
||||
|
@ -5,6 +5,7 @@ import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/xep_0030.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/helpers.dart";
|
||||
@ -23,7 +24,7 @@ class PresenceManager extends XmppManagerBase {
|
||||
String getName() => "PresenceManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "presence",
|
||||
callback: _onPresence
|
||||
@ -33,14 +34,14 @@ class PresenceManager extends XmppManagerBase {
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ capsXmlns ];
|
||||
|
||||
Future<bool> _onPresence(Stanza presence) async {
|
||||
Future<StanzaHandlerData> _onPresence(Stanza presence, StanzaHandlerData state) async {
|
||||
final attrs = getAttributes();
|
||||
switch (presence.type) {
|
||||
case "subscribed": {
|
||||
attrs.sendEvent(
|
||||
SubscriptionRequestReceivedEvent(from: JID.fromString(presence.from!))
|
||||
);
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
@ -51,7 +52,7 @@ class PresenceManager extends XmppManagerBase {
|
||||
getAttributes().sendEvent(PresenceReceivedEvent(JID.fromString(presence.from!), presence));
|
||||
}
|
||||
|
||||
return false;
|
||||
return state.copyWith(done: false);
|
||||
}
|
||||
|
||||
/// Returns the capability hash.
|
||||
|
@ -5,6 +5,7 @@ import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
class XmppRosterItem {
|
||||
@ -48,7 +49,7 @@ class RosterManager extends XmppManagerBase {
|
||||
String getName() => "RosterManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "iq",
|
||||
tagName: "query",
|
||||
@ -67,7 +68,7 @@ class RosterManager extends XmppManagerBase {
|
||||
_rosterVersion = ver;
|
||||
}
|
||||
|
||||
Future<bool> _onRosterPush(Stanza stanza) async {
|
||||
Future<StanzaHandlerData> _onRosterPush(Stanza stanza, StanzaHandlerData state) async {
|
||||
final attrs = getAttributes();
|
||||
final from = stanza.attributes["from"];
|
||||
final selfJid = attrs.getConnectionSettings().jid;
|
||||
@ -79,7 +80,7 @@ class RosterManager extends XmppManagerBase {
|
||||
// - a full JID of our own
|
||||
if (from != null && JID.fromString(stanza.attributes["from"]).toBare() != selfJid) {
|
||||
logger.warning("Roster push invalid! Unexpected from attribute: ${stanza.toXml()}");
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
final query = stanza.firstTag("query", xmlns: rosterXmlns)!;
|
||||
@ -87,7 +88,7 @@ class RosterManager extends XmppManagerBase {
|
||||
|
||||
if (item == null) {
|
||||
logger.warning("Received empty roster push");
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
if (query.attributes["ver"] != null) {
|
||||
@ -105,7 +106,7 @@ class RosterManager extends XmppManagerBase {
|
||||
));
|
||||
attrs.sendStanza(stanza.reply());
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
/// Requests the roster from the server. [lastVersion] refers to the last version
|
||||
|
@ -64,13 +64,10 @@ class TCPSocketWrapper extends BaseSocketWrapper {
|
||||
bool isSecure() => _secure;
|
||||
|
||||
bool _onBadCertificate(certificate, String domain) {
|
||||
_log.fine("Bad certificate: ${certificate.toString()}");
|
||||
final isExpired = certificate.endValidity.isAfter(DateTime.now());
|
||||
// TODO: Remove the kDebugMode once I am sure this works as it should
|
||||
return !isExpired && certificate.domain == domain && kDebugMode;
|
||||
|
||||
_log.fine("Bad certificate: ${certificate.toString()}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> _xep368Connect(String domain) async {
|
||||
|
@ -5,6 +5,7 @@ import "package:moxxyv2/xmpp/presence.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/helpers.dart";
|
||||
|
||||
class DiscoManager extends XmppManagerBase {
|
||||
@ -14,7 +15,7 @@ class DiscoManager extends XmppManagerBase {
|
||||
DiscoManager() : _features = List.empty(growable: true), super();
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
tagName: "query",
|
||||
tagXmlns: discoInfoXmlns,
|
||||
@ -54,8 +55,8 @@ class DiscoManager extends XmppManagerBase {
|
||||
/// May be overriden. Specifies the identities which will be returned in a disco info response.
|
||||
List<Identity> getIdentities() => const [ Identity(category: "client", type: "pc", name: "moxxmpp", lang: "en") ];
|
||||
|
||||
Future<bool> _onDiscoInfoRequest(Stanza stanza) async {
|
||||
if (stanza.type != "get") return false;
|
||||
Future<StanzaHandlerData> _onDiscoInfoRequest(Stanza stanza, StanzaHandlerData state) async {
|
||||
if (stanza.type != "get") return state;
|
||||
|
||||
final presence = getAttributes().getManagerById(presenceManager)! as PresenceManager;
|
||||
final query = stanza.firstTag("query")!;
|
||||
@ -93,7 +94,7 @@ class DiscoManager extends XmppManagerBase {
|
||||
)
|
||||
));
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
getAttributes().sendStanza(stanza.reply(
|
||||
@ -114,11 +115,11 @@ class DiscoManager extends XmppManagerBase {
|
||||
]
|
||||
));
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
Future<bool> _onDiscoItemsRequest(Stanza stanza) async {
|
||||
if (stanza.type != "get") return false;
|
||||
Future<StanzaHandlerData> _onDiscoItemsRequest(Stanza stanza, StanzaHandlerData state) async {
|
||||
if (stanza.type != "get") return state;
|
||||
|
||||
final query = stanza.firstTag("query")!;
|
||||
if (query.attributes["node"] != null) {
|
||||
@ -152,7 +153,7 @@ class DiscoManager extends XmppManagerBase {
|
||||
)
|
||||
));
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
getAttributes().sendStanza(stanza.reply(
|
||||
@ -163,7 +164,7 @@ class DiscoManager extends XmppManagerBase {
|
||||
)
|
||||
]
|
||||
));
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
/// Sends a disco info query to the (full) jid [entity], optionally with node=[node].
|
||||
|
@ -5,6 +5,7 @@ import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
class vCardPhoto {
|
||||
@ -33,8 +34,13 @@ class vCardManager extends XmppManagerBase {
|
||||
String getName() => "vCardManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
StanzaHandler(stanzaTag: "presence", tagName: "x", tagXmlns: vCardTempUpdate, callback: _onPresence)
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "presence",
|
||||
tagName: "x",
|
||||
tagXmlns: vCardTempUpdate,
|
||||
callback: _onPresence,
|
||||
)
|
||||
];
|
||||
|
||||
/// In case we get the avatar hash some other way.
|
||||
@ -42,7 +48,7 @@ class vCardManager extends XmppManagerBase {
|
||||
_lastHash[jid] = hash;
|
||||
}
|
||||
|
||||
Future<bool> _onPresence(Stanza presence) async {
|
||||
Future<StanzaHandlerData> _onPresence(Stanza presence, StanzaHandlerData state) async {
|
||||
final x = presence.firstTag("x", xmlns: vCardTempUpdate)!;
|
||||
final hash = x.firstTag("photo")!.innerText();
|
||||
|
||||
@ -64,7 +70,7 @@ class vCardManager extends XmppManagerBase {
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
vCardPhoto? _parseVCardPhoto(XMLNode? node) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
class PubSubItem {
|
||||
final String id;
|
||||
@ -25,11 +26,16 @@ class PubSubManager extends XmppManagerBase {
|
||||
String getName() => "pubsubManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
StanzaHandler(stanzaTag: "message", tagName: "event", tagXmlns: pubsubEventXmlns, callback: _onPubsubMessage)
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "event",
|
||||
tagXmlns: pubsubEventXmlns,
|
||||
callback: _onPubsubMessage
|
||||
)
|
||||
];
|
||||
|
||||
Future<bool> _onPubsubMessage(Stanza message) async {
|
||||
Future<StanzaHandlerData> _onPubsubMessage(Stanza message, StanzaHandlerData state) async {
|
||||
logger.finest("Received PubSub event");
|
||||
final event = message.firstTag("event", xmlns: pubsubEventXmlns)!;
|
||||
final items = event.firstTag("items")!;
|
||||
@ -44,7 +50,7 @@ class PubSubManager extends XmppManagerBase {
|
||||
from: message.attributes["from"]!
|
||||
));
|
||||
|
||||
return true;
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
|
||||
Future<bool> subscribe(String jid, String node) async {
|
||||
|
@ -1,3 +1,10 @@
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
/// A data class representing the jabber:x:oob tag.
|
||||
class OOBData {
|
||||
final String? url;
|
||||
@ -5,3 +12,39 @@ class OOBData {
|
||||
|
||||
const OOBData({ this.url, this.desc });
|
||||
}
|
||||
|
||||
class OOBManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "OOBName";
|
||||
|
||||
@override
|
||||
String getId() => oobManager;
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ oobDataXmlns ];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "x",
|
||||
tagXmlns: oobDataXmlns,
|
||||
callback: _onMessage,
|
||||
// Before the message manager
|
||||
priority: -99
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
final x = message.firstTag("x", xmlns: oobDataXmlns)!;
|
||||
final url = x.firstTag("url");
|
||||
final desc = x.firstTag("desc");
|
||||
|
||||
return state.copyWith(
|
||||
oob: OOBData(
|
||||
url: url?.innerText(),
|
||||
desc: desc?.innerText()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
XMLNode makeMessageDeliveryRequest() {
|
||||
return XMLNode.xmlns(
|
||||
@ -15,3 +22,57 @@ XMLNode makeMessageDeliveryResponse(String id) {
|
||||
attributes: { "id": id }
|
||||
);
|
||||
}
|
||||
|
||||
class MessageDeliveryReceiptManager extends XmppManagerBase {
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ deliveryXmlns ];
|
||||
|
||||
@override
|
||||
String getName() => "MessageDeliveryReceiptManager";
|
||||
|
||||
@override
|
||||
String getId() => messageDeliveryReceiptManager;
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "received",
|
||||
tagXmlns: deliveryXmlns,
|
||||
callback: _onDeliveryReceiptReceived,
|
||||
// Before the message handler
|
||||
priority: -99
|
||||
),
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "request",
|
||||
tagXmlns: deliveryXmlns,
|
||||
callback: _onDeliveryRequestReceived,
|
||||
// Before the message handler
|
||||
priority: -99
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onDeliveryRequestReceived(Stanza message, StanzaHandlerData state) async {
|
||||
return state.copyWith(deliveryReceiptRequested: true);
|
||||
}
|
||||
|
||||
Future<StanzaHandlerData> _onDeliveryReceiptReceived(Stanza message, StanzaHandlerData state) async {
|
||||
final received = message.firstTag("received", xmlns: deliveryXmlns)!;
|
||||
for (final item in message.children) {
|
||||
if (!["origin-id", "stanza-id", "delay"].contains(item.tag)) {
|
||||
logger.info("Won't handle stanza as delivery receipt because we found an '${item.tag}' element");
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
getAttributes().sendEvent(
|
||||
DeliveryReceiptReceivedEvent(
|
||||
from: JID.fromString(message.attributes["from"]!),
|
||||
id: received.attributes["id"]!
|
||||
)
|
||||
);
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0198/state.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0198/nonzas.dart";
|
||||
@ -123,17 +124,22 @@ class StreamManagementManager extends XmppManagerBase {
|
||||
];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getStanzaHandlers() => [
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
callback: _serverStanzaReceived
|
||||
callback: _onServerStanzaReceived
|
||||
)
|
||||
];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getOutgoingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
callback: _onClientStanzaSent
|
||||
)
|
||||
];
|
||||
|
||||
@override
|
||||
void onXmppEvent(XmppEvent event) {
|
||||
if (event is StanzaSentEvent) {
|
||||
_onClientStanzaSent(event.stanza);
|
||||
} else if (event is SendPingEvent) {
|
||||
if (event is SendPingEvent) {
|
||||
if (isStreamManagementEnabled()) {
|
||||
_sendAckRequestPing();
|
||||
} else {
|
||||
@ -220,13 +226,13 @@ class StreamManagementManager extends XmppManagerBase {
|
||||
}
|
||||
|
||||
/// Called whenever we receive a stanza from the server.
|
||||
Future<bool> _serverStanzaReceived(stanza) async {
|
||||
Future<StanzaHandlerData> _onServerStanzaReceived(Stanza stanza, StanzaHandlerData state) async {
|
||||
_incrementS2C();
|
||||
return false;
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Called whenever we send a stanza.
|
||||
void _onClientStanzaSent(Stanza stanza) {
|
||||
Future<StanzaHandlerData> _onClientStanzaSent(Stanza stanza, StanzaHandlerData state) async {
|
||||
_startTimer();
|
||||
|
||||
_incrementC2S();
|
||||
@ -237,6 +243,8 @@ class StreamManagementManager extends XmppManagerBase {
|
||||
if (isStreamManagementEnabled()) {
|
||||
getAttributes().sendNonza(StreamManagementRequestNonza());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/// Removes all stanzas in the unacked queue that have a sequence number less-than or
|
||||
|
@ -1,10 +1,14 @@
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0297.dart";
|
||||
|
||||
|
||||
class CarbonsManager extends XmppManagerBase {
|
||||
bool _isEnabled;
|
||||
@ -17,6 +21,32 @@ class CarbonsManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "CarbonsManager";
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "received",
|
||||
tagXmlns: carbonsXmlns,
|
||||
callback: _onMessage,
|
||||
// Before all managers the message manager depends on
|
||||
priority: -98
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
final from = JID.fromString(message.attributes["from"]!);
|
||||
final received = message.firstTag("received", xmlns: carbonsXmlns)!;
|
||||
if (!isCarbonValid(from)) return state.copyWith(done: true);
|
||||
|
||||
final forwarded = received.firstTag("forwarded", xmlns: forwardedXmlns)!;
|
||||
final carbon = unpackForwarded(forwarded);
|
||||
|
||||
return state.copyWith(
|
||||
isCarbon: true,
|
||||
stanza: carbon
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> enableCarbons() async {
|
||||
final result = await getAttributes().sendStanza(
|
||||
Stanza.iq(
|
||||
|
@ -1,5 +1,12 @@
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
|
||||
XMLNode makeChatMarkerMarkable() {
|
||||
return XMLNode.xmlns(
|
||||
@ -16,3 +23,44 @@ XMLNode makeChatMarker(String tag, String id) {
|
||||
attributes: { "id": id }
|
||||
);
|
||||
}
|
||||
|
||||
class ChatMarkerManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "ChatMarkerManager";
|
||||
|
||||
@override
|
||||
String getId() => chatMarkerManager;
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ chatMarkersXmlns ];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagXmlns: chatMarkersXmlns,
|
||||
callback: _onMessage,
|
||||
// Before the message handler
|
||||
priority: -99,
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
final marker = message.firstTagByXmlns(chatMarkersXmlns)!;
|
||||
|
||||
// Handle the <markable /> explicitly
|
||||
if (marker.tag == "markable") return state.copyWith(isMarkable: true);
|
||||
|
||||
if (!["received", "displayed", "acknowledged"].contains(marker.tag)) {
|
||||
logger.warning("Unknown message marker '${marker.tag}' found.");
|
||||
} else {
|
||||
getAttributes().sendEvent(ChatMarkerEvent(
|
||||
from: JID.fromString(message.from!),
|
||||
type: marker.tag,
|
||||
id: marker.attributes["id"]!,
|
||||
));
|
||||
}
|
||||
|
||||
return state.copyWith(done: true);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/cachemanager.dart";
|
||||
|
||||
/// Represents data provided by XEP-0359.
|
||||
/// NOTE: [StableStanzaId.stanzaId] must not be confused with the actual id attribute of
|
||||
@ -19,3 +26,66 @@ XMLNode makeOriginIdElement(String id) {
|
||||
attributes: { "id": id }
|
||||
);
|
||||
}
|
||||
|
||||
class StableIdManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "StableIdManager";
|
||||
|
||||
@override
|
||||
String getId() => stableIdManager;
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ stableIdXmlns ];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
callback: _onMessage,
|
||||
// Before the MessageManager
|
||||
priority: -99
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
final from = JID.fromString(message.attributes["from"]!);
|
||||
String? originId;
|
||||
String? stanzaId;
|
||||
String? stanzaIdBy;
|
||||
final originIdTag = message.firstTag("origin-id", xmlns: stableIdXmlns);
|
||||
final stanzaIdTag = message.firstTag("stanza-id", xmlns: stableIdXmlns);
|
||||
if (originIdTag != null || stanzaIdTag != null) {
|
||||
logger.finest("Found Unique and Stable Stanza Id tag");
|
||||
final attrs = getAttributes();
|
||||
final cache = attrs.getManagerById(discoCacheManager) as DiscoCacheManager?;
|
||||
if (cache != null) {
|
||||
final info = await cache.getInfoByJid(from.toString());
|
||||
if (info != null) {
|
||||
logger.finest("Got info for ${from.toString()}");
|
||||
if (info.features.contains(stableIdXmlns)) {
|
||||
logger.finest("${from.toString()} supports $stableIdXmlns.");
|
||||
|
||||
if (originIdTag != null) {
|
||||
originId = originIdTag.attributes["id"]!;
|
||||
}
|
||||
|
||||
if (stanzaIdTag != null) {
|
||||
stanzaId = stanzaIdTag.attributes["id"]!;
|
||||
stanzaIdBy = stanzaIdTag.attributes["by"]!;
|
||||
}
|
||||
} else {
|
||||
logger.finest("${from.toString()} does not support $stableIdXmlns. Ignoring... ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state.copyWith(
|
||||
stableId: StableStanzaId(
|
||||
originId: originId,
|
||||
stanzaId: stanzaId,
|
||||
stanzaIdBy: stanzaIdBy
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/staging/file_thumbnails.dart";
|
||||
|
||||
class StatelessMediaSharingData {
|
||||
@ -53,3 +58,36 @@ StatelessMediaSharingData parseSIMSElement(XMLNode node) {
|
||||
thumbnails: thumbnails
|
||||
);
|
||||
}
|
||||
|
||||
class SIMSManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "SIMSManager";
|
||||
|
||||
@override
|
||||
String getId() => simsManager;
|
||||
|
||||
@override
|
||||
List<String> getDiscoFeatures() => [ simsXmlns ];
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
callback: _onMessage,
|
||||
tagName: "reference",
|
||||
tagXmlns: referenceXmlns,
|
||||
// Before the message handler
|
||||
priority: -99
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
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));
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/base.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/managers/namespaces.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0446.dart";
|
||||
|
||||
class StatelessFileSharingData {
|
||||
@ -23,3 +28,31 @@ StatelessFileSharingData parseSFSElement(XMLNode node) {
|
||||
url: url
|
||||
);
|
||||
}
|
||||
|
||||
class SFSManager extends XmppManagerBase {
|
||||
@override
|
||||
String getName() => "SFSManager";
|
||||
|
||||
@override
|
||||
String getId() => sfsManager;
|
||||
|
||||
@override
|
||||
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||
StanzaHandler(
|
||||
stanzaTag: "message",
|
||||
tagName: "file-sharing",
|
||||
tagXmlns: sfsXmlns,
|
||||
callback: _onMessage,
|
||||
// Before the message handler
|
||||
priority: -99,
|
||||
)
|
||||
];
|
||||
|
||||
Future<StanzaHandlerData> _onMessage(Stanza message, StanzaHandlerData state) async {
|
||||
final sfs = message.firstTag("file-sharing", xmlns: sfsXmlns)!;
|
||||
|
||||
return state.copyWith(
|
||||
sfs: parseSFSElement(sfs)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import "package:test/test.dart";
|
||||
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
|
||||
final stanza1 = Stanza.iq(children: [
|
||||
XMLNode.xmlns(tag: "tag", xmlns: "owo")
|
||||
@ -13,7 +14,7 @@ final stanza2 = Stanza.message(children: [
|
||||
|
||||
void main() {
|
||||
test("match all", () {
|
||||
final handler = StanzaHandler(callback: (_) async => true);
|
||||
final handler = StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true,stanza));
|
||||
|
||||
expect(handler.matches(Stanza.iq()), true);
|
||||
expect(handler.matches(Stanza.message()), true);
|
||||
@ -22,7 +23,10 @@ void main() {
|
||||
expect(handler.matches(stanza2), true);
|
||||
});
|
||||
test("xmlns matching", () {
|
||||
final handler = StanzaHandler(callback: (_) async => true, tagXmlns: "owo");
|
||||
final handler = StanzaHandler(
|
||||
callback: (stanza, _) async => StanzaHandlerData(true, stanza),
|
||||
tagXmlns: "owo"
|
||||
);
|
||||
|
||||
expect(handler.matches(Stanza.iq()), false);
|
||||
expect(handler.matches(Stanza.message()), false);
|
||||
@ -32,9 +36,9 @@ void main() {
|
||||
});
|
||||
test("stanzaTag matching", () {
|
||||
bool run = false;
|
||||
final handler = StanzaHandler(callback: (_) async {
|
||||
final handler = StanzaHandler(callback: (stanza, _) async {
|
||||
run = true;
|
||||
return true;
|
||||
return StanzaHandlerData(true, stanza);
|
||||
}, stanzaTag: "iq");
|
||||
|
||||
expect(handler.matches(Stanza.iq()), true);
|
||||
@ -43,11 +47,14 @@ void main() {
|
||||
expect(handler.matches(stanza1), true);
|
||||
expect(handler.matches(stanza2), false);
|
||||
|
||||
handler.callback(stanza2);
|
||||
handler.callback(stanza2, StanzaHandlerData(false, stanza2));
|
||||
expect(run, true);
|
||||
});
|
||||
test("tagName matching", () {
|
||||
final handler = StanzaHandler(callback: (_) async => true, tagName: "tag");
|
||||
final handler = StanzaHandler(
|
||||
callback: (stanza, _) async => StanzaHandlerData(true, stanza),
|
||||
tagName: "tag"
|
||||
);
|
||||
|
||||
expect(handler.matches(Stanza.iq()), false);
|
||||
expect(handler.matches(Stanza.message()), false);
|
||||
@ -56,7 +63,12 @@ void main() {
|
||||
expect(handler.matches(stanza2), false);
|
||||
});
|
||||
test("combined matching", () {
|
||||
final handler = StanzaHandler(callback: (_) async => true, tagName: "tag", stanzaTag: "iq", tagXmlns: "owo");
|
||||
final handler = StanzaHandler(
|
||||
callback: (stanza, _) async => StanzaHandlerData(true, stanza),
|
||||
tagName: "tag",
|
||||
stanzaTag: "iq",
|
||||
tagXmlns: "owo"
|
||||
);
|
||||
|
||||
expect(handler.matches(Stanza.iq()), false);
|
||||
expect(handler.matches(Stanza.message()), false);
|
||||
@ -64,4 +76,18 @@ void main() {
|
||||
expect(handler.matches(stanza1), true);
|
||||
expect(handler.matches(stanza2), false);
|
||||
});
|
||||
|
||||
test("sorting", () {
|
||||
final handlerList = [
|
||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, stanza), tagName: "1", priority: 100),
|
||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, stanza), tagName: "2"),
|
||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, stanza), tagName: "3", priority: 50)
|
||||
];
|
||||
|
||||
handlerList.sort(stanzaHandlerSortComparator);
|
||||
|
||||
expect(handlerList[0].tagName, "1");
|
||||
expect(handlerList[1].tagName, "3");
|
||||
expect(handlerList[2].tagName, "2");
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import "package:moxxyv2/xmpp/managers/attributes.dart";
|
||||
import "package:moxxyv2/xmpp/stringxml.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/stanza.dart";
|
||||
import "package:moxxyv2/xmpp/settings.dart";
|
||||
import "package:moxxyv2/xmpp/jid.dart";
|
||||
import "package:moxxyv2/xmpp/managers/attributes.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0198/xep_0198.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0198/state.dart";
|
||||
|
||||
@ -11,6 +12,18 @@ import "../helpers/xml.dart";
|
||||
|
||||
import "package:test/test.dart";
|
||||
|
||||
Future<void> runIncomingStanzaHandlers(StreamManagementManager man, Stanza stanza) async {
|
||||
for (final handler in man.getIncomingStanzaHandlers()) {
|
||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, stanza));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> runOutgoingStanzaHandlers(StreamManagementManager man, Stanza stanza) async {
|
||||
for (final handler in man.getOutgoingStanzaHandlers()) {
|
||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, stanza));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
final stanza = Stanza(
|
||||
to: "some.user@server.example",
|
||||
@ -46,14 +59,14 @@ void main() {
|
||||
manager.onXmppEvent(StreamManagementEnabledEvent(id: "0", resource: "h"));
|
||||
|
||||
// Receive a fake stanza
|
||||
await manager.runStanzaHandlers(stanza);
|
||||
await manager.runStanzaHandlers(stanza);
|
||||
await runIncomingStanzaHandlers(manager, stanza);
|
||||
await runIncomingStanzaHandlers(manager, stanza);
|
||||
expect(manager.state.s2c, 2, reason: "The S2C counter must count correctly");
|
||||
|
||||
// Send some fake stanzas
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
expect(manager.state.c2s, 3, reason: "The C2S counter must count correctly");
|
||||
|
||||
final ack = XMLNode.xmlns(tag: "a", xmlns: "urn:xmpp:sm:3", attributes: { "h": "3" });
|
||||
@ -63,7 +76,7 @@ void main() {
|
||||
expect(manager.state.s2c, 2, reason: "Sending stanzas must not change the S2C counter");
|
||||
|
||||
// Send a stanza which we will not acknowledge
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
expect(manager.state.c2s, 4, reason: "Sending a stanza must increment the C2S counter");
|
||||
await manager.runNonzaHandlers(ack);
|
||||
manager.onTimerElapsed(null, ignoreTimestamps: true);
|
||||
@ -101,9 +114,9 @@ void main() {
|
||||
manager.register(attributes);
|
||||
|
||||
// Send some stanzas
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
manager.onXmppEvent(StanzaSentEvent(stanza: stanza));
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
runOutgoingStanzaHandlers(manager, stanza);
|
||||
|
||||
// Simulate a resumption
|
||||
manager.onXmppEvent(StreamResumedEvent(h: 2));
|
||||
|
@ -9,8 +9,9 @@ import "package:moxxyv2/xmpp/presence.dart";
|
||||
import "package:moxxyv2/xmpp/roster.dart";
|
||||
import "package:moxxyv2/xmpp/events.dart";
|
||||
import "package:moxxyv2/xmpp/managers/attributes.dart";
|
||||
import "package:moxxyv2/xmpp/managers/handlers.dart";
|
||||
import "package:moxxyv2/xmpp/managers/data.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/xep_0030.dart";
|
||||
import "package:moxxyv2/xmpp/xeps/xep_0030/cachemanager.dart";
|
||||
|
||||
import "helpers/xmpp.dart";
|
||||
|
||||
@ -40,14 +41,9 @@ Future<bool> testRosterManager(String bareJid, String resource, String stanzaStr
|
||||
));
|
||||
|
||||
final stanza = Stanza.fromXMLNode(XMLNode.fromString(stanzaString));
|
||||
await Future.forEach(
|
||||
roster.getStanzaHandlers(),
|
||||
(StanzaHandler handler) async {
|
||||
if (handler.matches(stanza)) {
|
||||
await handler.callback(stanza);
|
||||
}
|
||||
}
|
||||
);
|
||||
for (final handler in roster.getIncomingStanzaHandlers()) {
|
||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, stanza));
|
||||
}
|
||||
|
||||
return eventTriggered;
|
||||
}
|
||||
@ -216,6 +212,7 @@ void main() {
|
||||
),
|
||||
]
|
||||
);
|
||||
// TODO: This test is broken since we query the server and enable carbons
|
||||
final XmppConnection conn = XmppConnection(socket: fakeSocket);
|
||||
conn.setConnectionSettings(ConnectionSettings(
|
||||
jid: JID.fromString("polynomdivision@test.server"),
|
||||
@ -225,6 +222,7 @@ void main() {
|
||||
));
|
||||
conn.registerManager(RosterManager());
|
||||
conn.registerManager(DiscoManager());
|
||||
conn.registerManager(DiscoCacheManager());
|
||||
conn.registerManager(PresenceManager());
|
||||
|
||||
await conn.connect();
|
||||
@ -509,14 +507,10 @@ void main() {
|
||||
// NOTE: Based on https://gultsch.de/gajim_roster_push_and_message_interception.html
|
||||
// NOTE: Added a from attribute as a server would add it itself.
|
||||
final maliciousStanza = Stanza.fromXMLNode(XMLNode.fromString("<iq type=\"set\" from=\"eve@siacs.eu/bbbbb\" to=\"some.user@example.server/aaaaa\"><query xmlns='jabber:iq:roster'><item subscription=\"both\" jid=\"eve@siacs.eu\" name=\"Bob\" /></query></iq>"));
|
||||
await Future.forEach(
|
||||
roster.getStanzaHandlers(),
|
||||
(StanzaHandler handler) async {
|
||||
if (handler.matches(maliciousStanza)) {
|
||||
await handler.callback(maliciousStanza);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
for (final handler in roster.getIncomingStanzaHandlers()) {
|
||||
if (handler.matches(maliciousStanza)) await handler.callback(maliciousStanza, StanzaHandlerData(false, maliciousStanza));
|
||||
}
|
||||
|
||||
expect(eventTriggered, false, reason: "Was able to inject a malicious roster push");
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user