diff --git a/packages/moxxmpp/lib/src/xeps/xep_0352.dart b/packages/moxxmpp/lib/src/xeps/xep_0352.dart index 6ac38c4..1c339df 100644 --- a/packages/moxxmpp/lib/src/xeps/xep_0352.dart +++ b/packages/moxxmpp/lib/src/xeps/xep_0352.dart @@ -5,6 +5,7 @@ import 'package:moxxmpp/src/negotiators/namespaces.dart'; import 'package:moxxmpp/src/negotiators/negotiator.dart'; import 'package:moxxmpp/src/stringxml.dart'; import 'package:moxxmpp/src/types/result.dart'; +import 'package:moxxmpp/src/xeps/xep_0386.dart'; class CSIActiveNonza extends XMLNode { CSIActiveNonza() @@ -23,7 +24,8 @@ class CSIInactiveNonza extends XMLNode { } /// A Stub negotiator that is just for "intercepting" the stream feature. -class CSINegotiator extends XmppFeatureNegotiatorBase { +class CSINegotiator extends XmppFeatureNegotiatorBase + implements Bind2FeatureNegotiator { CSINegotiator() : super(11, false, csiXmlns, csiNegotiator); /// True if CSI is supported. False otherwise. @@ -40,19 +42,43 @@ class CSINegotiator extends XmppFeatureNegotiatorBase { return const Result(NegotiatorState.done); } + @override + Future> onBind2FeaturesReceived( + List bind2Features, + ) async { + if (!bind2Features.contains(csiXmlns)) { + return []; + } + + final active = attributes.getManagerById(csiManager)!.isActive; + return [ + if (active) CSIActiveNonza() else CSIInactiveNonza(), + ]; + } + @override void reset() { _supported = false; super.reset(); } + + @override + Future postRegisterCallback() async { + attributes + .getNegotiatorById(bind2Negotiator) + ?.registerNegotiator(this); + } } /// The manager requires a CSINegotiator to be registered as a feature negotiator. class CSIManager extends XmppManagerBase { CSIManager() : super(csiManager); + /// Flag indicating whether the application is currently active and the CSI + /// traffic optimisation should be disabled (true). bool _isActive = true; + bool get isActive => _isActive; @override Future isSupported() async { @@ -71,23 +97,31 @@ class CSIManager extends XmppManagerBase { } } - /// Tells the server to top optimizing traffic - Future setActive() async { + /// Tells the server to stop optimizing traffic. + /// If [sendNonza] is false, then no nonza is sent. This is useful + /// for setting up the CSI manager for Bind2. + Future setActive({bool sendNonza = true}) async { _isActive = true; - final attrs = getAttributes(); - if (await isSupported()) { - attrs.sendNonza(CSIActiveNonza()); + if (sendNonza) { + final attrs = getAttributes(); + if (await isSupported()) { + attrs.sendNonza(CSIActiveNonza()); + } } } /// Tells the server to optimize traffic following XEP-0352 - Future setInactive() async { + /// If [sendNonza] is false, then no nonza is sent. This is useful + /// for setting up the CSI manager for Bind2. + Future setInactive({bool sendNonza = true}) async { _isActive = false; - final attrs = getAttributes(); - if (await isSupported()) { - attrs.sendNonza(CSIInactiveNonza()); + if (sendNonza) { + final attrs = getAttributes(); + if (await isSupported()) { + attrs.sendNonza(CSIInactiveNonza()); + } } } } diff --git a/packages/moxxmpp/test/xeps/xep_0352_test.dart b/packages/moxxmpp/test/xeps/xep_0352_test.dart index 3981296..15192b1 100644 --- a/packages/moxxmpp/test/xeps/xep_0352_test.dart +++ b/packages/moxxmpp/test/xeps/xep_0352_test.dart @@ -1,5 +1,6 @@ import 'package:moxxmpp/moxxmpp.dart'; import 'package:test/test.dart'; +import '../helpers/logging.dart'; import '../helpers/xmpp.dart'; class MockedCSINegotiator extends CSINegotiator { @@ -28,6 +29,8 @@ T? getUnsupportedCSINegotiator(String id) { } void main() { + initLogger(); + group('Test the XEP-0352 implementation', () { test('Test setting the CSI state when CSI is unsupported', () { var nonzaSent = false; @@ -111,4 +114,95 @@ void main() { ..setInactive(); }); }); + + test('Test CSI with Bind2', () async { + final fakeSocket = StubTCPSocket([ + StringExpectation( + "", + ''' + + + + PLAIN + + + PLAIN + + + + + + + + + + + + ''', + ), + StanzaExpectation( + ''' + + + moxxmpp + PapaTutuWawa's awesome device + + AHBvbHlub21kaXZpc2lvbgBhYWFh + + + +''', + ''' + + polynomdivision@test.server/test-resource + + ''', + ), + ]); + final conn = XmppConnection( + TestingReconnectionPolicy(), + AlwaysConnectedConnectivityManager(), + fakeSocket, + )..setConnectionSettings( + ConnectionSettings( + jid: JID.fromString('polynomdivision@test.server'), + password: 'aaaa', + useDirectTLS: true, + ), + ); + final csi = CSIManager(); + await csi.setInactive(sendNonza: false); + await conn.registerManagers([ + RosterManager(TestingRosterStateManager('', [])), + DiscoManager([]), + csi, + ]); + await conn.registerFeatureNegotiators([ + SaslPlainNegotiator(), + ResourceBindingNegotiator(), + FASTSaslNegotiator(), + Bind2Negotiator(), + CSINegotiator(), + Sasl2Negotiator( + userAgent: const UserAgent( + id: 'd4565fa7-4d72-4749-b3d3-740edbf87770', + software: 'moxxmpp', + device: "PapaTutuWawa's awesome device", + ), + ), + ]); + + final result = await conn.connect( + waitUntilLogin: true, + shouldReconnect: false, + enableReconnectOnSuccess: false, + ); + expect(result.isType(), false); + expect(fakeSocket.getState(), 2); + }); }