Compare commits
5 Commits
d4416c8a47
...
76a9f7be7a
Author | SHA1 | Date | |
---|---|---|---|
76a9f7be7a | |||
afa3927720 | |||
5f36289f50 | |||
fbe3b90200 | |||
d7c13abde6 |
@ -38,6 +38,7 @@ void main(List<String> args) async {
|
|||||||
DiscoManager([]),
|
DiscoManager([]),
|
||||||
PubSubManager(),
|
PubSubManager(),
|
||||||
MessageManager(),
|
MessageManager(),
|
||||||
|
StableIdManager(),
|
||||||
MUCManager(),
|
MUCManager(),
|
||||||
]);
|
]);
|
||||||
await connection.registerFeatureNegotiators([
|
await connection.registerFeatureNegotiators([
|
||||||
@ -57,8 +58,28 @@ void main(List<String> args) async {
|
|||||||
}
|
}
|
||||||
Logger.root.info('Connected.');
|
Logger.root.info('Connected.');
|
||||||
|
|
||||||
|
// Print received messages.
|
||||||
|
connection
|
||||||
|
.asBroadcastStream()
|
||||||
|
.where((event) => event is MessageEvent)
|
||||||
|
.listen((event) {
|
||||||
|
event as MessageEvent;
|
||||||
|
|
||||||
|
// Ignore messages with no <body />
|
||||||
|
final body = event.get<MessageBodyData>()?.body;
|
||||||
|
if (body == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print('=====> [${event.from}] $body');
|
||||||
|
});
|
||||||
|
|
||||||
// Join room
|
// Join room
|
||||||
await connection.getManagerById<MUCManager>(mucManager)!.joinRoom(muc, nick);
|
await connection.getManagerById<MUCManager>(mucManager)!.joinRoom(
|
||||||
|
muc,
|
||||||
|
nick,
|
||||||
|
maxHistoryStanzas: 0,
|
||||||
|
);
|
||||||
|
|
||||||
final repl = Repl(prompt: '> ');
|
final repl = Repl(prompt: '> ');
|
||||||
await for (final line in repl.runAsync()) {
|
await for (final line in repl.runAsync()) {
|
||||||
@ -68,6 +89,11 @@ void main(List<String> args) async {
|
|||||||
muc,
|
muc,
|
||||||
TypedMap<StanzaHandlerExtension>.fromList([
|
TypedMap<StanzaHandlerExtension>.fromList([
|
||||||
MessageBodyData(line),
|
MessageBodyData(line),
|
||||||
|
StableIdData(
|
||||||
|
// NOTE: Don't do this. Use a UUID.
|
||||||
|
DateTime.now().millisecondsSinceEpoch.toString(),
|
||||||
|
null,
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
type: 'groupchat');
|
type: 'groupchat');
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ description: A collection of samples for moxxmpp.
|
|||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.18.0 <3.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
args: 2.4.1
|
args: 2.4.1
|
||||||
|
54
flake.lock
54
flake.lock
@ -7,11 +7,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689798050,
|
"lastModified": 1694377165,
|
||||||
"narHash": "sha256-ZyFPra7N0MF803o55dYQQyX9b/BmXr6QTCyN7slRThY=",
|
"narHash": "sha256-NeIlZIElbkbKaNK5SZv6ULcFT/UGIICb3q7GPpkf9jk=",
|
||||||
"owner": "tadfisher",
|
"owner": "tadfisher",
|
||||||
"repo": "android-nixpkgs",
|
"repo": "android-nixpkgs",
|
||||||
"rev": "9aa0e2990da86de8ca203af313668851dcb9ea6e",
|
"rev": "b020dc733ee69393841a50cf94d45735d5a5a57a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -29,11 +29,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1688380630,
|
"lastModified": 1693833206,
|
||||||
"narHash": "sha256-8ilApWVb1mAi4439zS3iFeIT0ODlbrifm/fegWwgHjA=",
|
"narHash": "sha256-wHOY0nnD6gWj8u9uI85/YlsganYyWRK1hLFZulZwfmY=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "devshell",
|
"repo": "devshell",
|
||||||
"rev": "f9238ec3d75cefbb2b42a44948c4e8fb1ae9a205",
|
"rev": "65114ea495a8d3cc1352368bf170d67ef005aa5a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -47,11 +47,11 @@
|
|||||||
"systems": "systems_2"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689068808,
|
"lastModified": 1692799911,
|
||||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -61,12 +61,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils_2": {
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_3"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667395993,
|
"lastModified": 1692799911,
|
||||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -77,11 +80,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689679375,
|
"lastModified": 1694183432,
|
||||||
"narHash": "sha256-LHUC52WvyVDi9PwyL1QCpaxYWBqp4ir4iL6zgOkmcb8=",
|
"narHash": "sha256-YyPGNapgZNNj51ylQMw9lAgvxtM2ai1HZVUu3GS8Fng=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "684c17c429c42515bafb3ad775d2a710947f3d67",
|
"rev": "db9208ab987cdeeedf78ad9b4cf3c55f5ebd269b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -93,11 +96,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1689752456,
|
"lastModified": 1694343207,
|
||||||
"narHash": "sha256-VOChdECcEI8ixz8QY+YC4JaNEFwQd1V8bA0G4B28Ki0=",
|
"narHash": "sha256-jWi7OwFxU5Owi4k2JmiL1sa/OuBCQtpaAesuj5LXC8w=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7f256d7da238cb627ef189d56ed590739f42f13b",
|
"rev": "78058d810644f5ed276804ce7ea9e82d92bee293",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -143,6 +146,21 @@
|
|||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"systems_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
};
|
};
|
||||||
in pkgs.mkShell {
|
in pkgs.mkShell {
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
flutter37 pinnedJDK sdk dart # Dart
|
flutter pinnedJDK sdk dart # Dart
|
||||||
gitlint # Code hygiene
|
gitlint # Code hygiene
|
||||||
ripgrep # General utilities
|
ripgrep # General utilities
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ class XmppConnection {
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
newStanza,
|
newStanza,
|
||||||
TypedMap(),
|
details.extensions ?? TypedMap(),
|
||||||
encrypted: details.encrypted,
|
encrypted: details.encrypted,
|
||||||
shouldEncrypt: details.shouldEncrypt,
|
shouldEncrypt: details.shouldEncrypt,
|
||||||
forceEncryption: details.forceEncryption,
|
forceEncryption: details.forceEncryption,
|
||||||
|
@ -66,7 +66,7 @@ class MessageManager extends XmppManagerBase {
|
|||||||
stanzaTag: 'message',
|
stanzaTag: 'message',
|
||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
priority: messageHandlerPriority,
|
priority: messageHandlerPriority,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -117,6 +117,7 @@ class MessageManager extends XmppManagerBase {
|
|||||||
.flattened
|
.flattened
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
extensions: extensions,
|
||||||
awaitable: false,
|
awaitable: false,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -66,7 +66,7 @@ class PresenceManager extends XmppManagerBase {
|
|||||||
stanzaTag: 'presence',
|
stanzaTag: 'presence',
|
||||||
callback: _onPresence,
|
callback: _onPresence,
|
||||||
priority: presenceHandlerPriority,
|
priority: presenceHandlerPriority,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -122,7 +122,7 @@ class RosterManager extends XmppManagerBase {
|
|||||||
tagName: 'query',
|
tagName: 'query',
|
||||||
tagXmlns: rosterXmlns,
|
tagXmlns: rosterXmlns,
|
||||||
callback: _onRosterPush,
|
callback: _onRosterPush,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -277,7 +277,7 @@ class RosterManager extends XmppManagerBase {
|
|||||||
attributes: {
|
attributes: {
|
||||||
'ver': await _stateManager.getRosterVersion() ?? '',
|
'ver': await _stateManager.getRosterVersion() ?? '',
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -319,14 +319,12 @@ class RosterManager extends XmppManagerBase {
|
|||||||
tag: 'item',
|
tag: 'item',
|
||||||
attributes: <String, String>{
|
attributes: <String, String>{
|
||||||
'jid': jid,
|
'jid': jid,
|
||||||
...title == jid.split('@')[0]
|
if (title == jid.split('@')[0]) 'name': title,
|
||||||
? <String, String>{}
|
|
||||||
: <String, String>{'name': title}
|
|
||||||
},
|
},
|
||||||
children: (groups ?? [])
|
children: (groups ?? [])
|
||||||
.map((group) => XMLNode(tag: 'group', text: group))
|
.map((group) => XMLNode(tag: 'group', text: group))
|
||||||
.toList(),
|
.toList(),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -357,13 +355,13 @@ class RosterManager extends XmppManagerBase {
|
|||||||
children: [
|
children: [
|
||||||
XMLNode(
|
XMLNode(
|
||||||
tag: 'item',
|
tag: 'item',
|
||||||
attributes: <String, String>{
|
attributes: {
|
||||||
'jid': jid,
|
'jid': jid,
|
||||||
'subscription': 'remove'
|
'subscription': 'remove',
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -7,6 +7,7 @@ import 'package:moxxmpp/src/util/typed_map.dart';
|
|||||||
class StanzaDetails {
|
class StanzaDetails {
|
||||||
const StanzaDetails(
|
const StanzaDetails(
|
||||||
this.stanza, {
|
this.stanza, {
|
||||||
|
this.extensions,
|
||||||
this.addId = true,
|
this.addId = true,
|
||||||
this.awaitable = true,
|
this.awaitable = true,
|
||||||
this.shouldEncrypt = true,
|
this.shouldEncrypt = true,
|
||||||
@ -19,6 +20,9 @@ class StanzaDetails {
|
|||||||
/// The stanza to send.
|
/// The stanza to send.
|
||||||
final Stanza stanza;
|
final Stanza stanza;
|
||||||
|
|
||||||
|
/// The extension data used for constructing the stanza.
|
||||||
|
final TypedMap<StanzaHandlerExtension>? extensions;
|
||||||
|
|
||||||
/// Flag indicating whether a stanza id should be added before sending.
|
/// Flag indicating whether a stanza id should be added before sending.
|
||||||
final bool addId;
|
final bool addId;
|
||||||
|
|
||||||
@ -244,15 +248,14 @@ XMLNode buildErrorElement(String type, String condition, {String? text}) {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: condition,
|
tag: condition,
|
||||||
xmlns: fullStanzaXmlns,
|
xmlns: fullStanzaXmlns,
|
||||||
children: text != null
|
children: [
|
||||||
? [
|
if (text != null)
|
||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'text',
|
tag: 'text',
|
||||||
xmlns: fullStanzaXmlns,
|
xmlns: fullStanzaXmlns,
|
||||||
text: text,
|
text: text,
|
||||||
)
|
),
|
||||||
]
|
],
|
||||||
: [],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -10,14 +10,14 @@ class DataFormOption {
|
|||||||
XMLNode toXml() {
|
XMLNode toXml() {
|
||||||
return XMLNode(
|
return XMLNode(
|
||||||
tag: 'option',
|
tag: 'option',
|
||||||
attributes: label != null
|
attributes: {
|
||||||
? <String, dynamic>{'label': label}
|
if (label != null) 'label': label,
|
||||||
: <String, dynamic>{},
|
},
|
||||||
children: [
|
children: [
|
||||||
XMLNode(
|
XMLNode(
|
||||||
tag: 'value',
|
tag: 'value',
|
||||||
text: value,
|
text: value,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -45,19 +45,22 @@ class DataFormField {
|
|||||||
return XMLNode(
|
return XMLNode(
|
||||||
tag: 'field',
|
tag: 'field',
|
||||||
attributes: <String, dynamic>{
|
attributes: <String, dynamic>{
|
||||||
...varAttr != null
|
if (varAttr != null) 'var': varAttr,
|
||||||
? <String, dynamic>{'var': varAttr}
|
if (type != null) 'type': type,
|
||||||
: <String, dynamic>{},
|
if (label != null) 'label': label,
|
||||||
...type != null ? <String, dynamic>{'type': type} : <String, dynamic>{},
|
|
||||||
...label != null
|
|
||||||
? <String, dynamic>{'label': label}
|
|
||||||
: <String, dynamic>{}
|
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
...description != null ? [XMLNode(tag: 'desc', text: description)] : [],
|
if (description != null)
|
||||||
...isRequired ? [XMLNode(tag: 'required')] : [],
|
XMLNode(
|
||||||
|
tag: 'desc',
|
||||||
|
text: description,
|
||||||
|
),
|
||||||
|
if (isRequired)
|
||||||
|
XMLNode(
|
||||||
|
tag: 'required',
|
||||||
|
),
|
||||||
...values.map((value) => XMLNode(tag: 'value', text: value)),
|
...values.map((value) => XMLNode(tag: 'value', text: value)),
|
||||||
...options.map((option) => option.toXml())
|
...options.map((option) => option.toXml()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,10 @@ Stanza buildDiscoInfoQueryStanza(JID entity, String? node) {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'query',
|
tag: 'query',
|
||||||
xmlns: discoInfoXmlns,
|
xmlns: discoInfoXmlns,
|
||||||
attributes: node != null ? {'node': node} : {},
|
attributes: {
|
||||||
)
|
if (node != null) 'node': node,
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -27,8 +29,10 @@ Stanza buildDiscoItemsQueryStanza(JID entity, {String? node}) {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'query',
|
tag: 'query',
|
||||||
xmlns: discoItemsXmlns,
|
xmlns: discoItemsXmlns,
|
||||||
attributes: node != null ? {'node': node} : {},
|
attributes: {
|
||||||
)
|
if (node != null) 'node': node,
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,11 @@ class Identity {
|
|||||||
XMLNode toXMLNode() {
|
XMLNode toXMLNode() {
|
||||||
return XMLNode(
|
return XMLNode(
|
||||||
tag: 'identity',
|
tag: 'identity',
|
||||||
attributes: <String, dynamic>{
|
attributes: {
|
||||||
'category': category,
|
'category': category,
|
||||||
'type': type,
|
'type': type,
|
||||||
'name': name,
|
'name': name,
|
||||||
...lang == null
|
if (lang != null) 'xml:lang': lang,
|
||||||
? <String, dynamic>{}
|
|
||||||
: <String, dynamic>{'xml:lang': lang}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,22 @@ class RoomInformation {
|
|||||||
final String name;
|
final String name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The used message-id and an optional origin-id.
|
||||||
|
typedef PendingMessage = (String, String?);
|
||||||
|
|
||||||
class RoomState {
|
class RoomState {
|
||||||
RoomState({
|
RoomState({required this.roomJid, this.nick, required this.joined}) {
|
||||||
required this.roomJid,
|
pendingMessages = List<PendingMessage>.empty(growable: true);
|
||||||
this.nick,
|
}
|
||||||
});
|
|
||||||
final JID roomJid;
|
/// The JID of the room.
|
||||||
String? nick;
|
final JID roomJid;
|
||||||
|
|
||||||
|
/// The nick we're joined with.
|
||||||
|
String? nick;
|
||||||
|
|
||||||
|
/// Flag whether we're joined and can process messages
|
||||||
|
bool joined;
|
||||||
|
|
||||||
|
late final List<PendingMessage> pendingMessages;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import 'package:moxlib/moxlib.dart';
|
import 'package:moxlib/moxlib.dart';
|
||||||
|
import 'package:moxxmpp/src/events.dart';
|
||||||
import 'package:moxxmpp/src/jid.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/handlers.dart';
|
||||||
import 'package:moxxmpp/src/managers/namespaces.dart';
|
import 'package:moxxmpp/src/managers/namespaces.dart';
|
||||||
import 'package:moxxmpp/src/namespaces.dart';
|
import 'package:moxxmpp/src/namespaces.dart';
|
||||||
import 'package:moxxmpp/src/stanza.dart';
|
import 'package:moxxmpp/src/stanza.dart';
|
||||||
@ -9,8 +12,13 @@ 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_0045/errors.dart';
|
import 'package:moxxmpp/src/xeps/xep_0045/errors.dart';
|
||||||
import 'package:moxxmpp/src/xeps/xep_0045/types.dart';
|
import 'package:moxxmpp/src/xeps/xep_0045/types.dart';
|
||||||
|
import 'package:moxxmpp/src/xeps/xep_0359.dart';
|
||||||
|
import 'package:synchronized/extension.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
|
/// (Room JID, nickname)
|
||||||
|
typedef MUCRoomJoin = (JID, String);
|
||||||
|
|
||||||
class MUCManager extends XmppManagerBase {
|
class MUCManager extends XmppManagerBase {
|
||||||
MUCManager() : super(mucManager);
|
MUCManager() : super(mucManager);
|
||||||
|
|
||||||
@ -23,6 +31,78 @@ class MUCManager extends XmppManagerBase {
|
|||||||
/// Cache lock
|
/// Cache lock
|
||||||
final Lock _cacheLock = Lock();
|
final Lock _cacheLock = Lock();
|
||||||
|
|
||||||
|
/// Flag indicating whether we joined the rooms added to the room list with
|
||||||
|
/// [prepareRoomList].
|
||||||
|
bool _joinedPreparedRooms = true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<StanzaHandler> getIncomingStanzaHandlers() => [
|
||||||
|
StanzaHandler(
|
||||||
|
stanzaTag: 'message',
|
||||||
|
callback: _onMessage,
|
||||||
|
// Before the message handler
|
||||||
|
priority: -99,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<StanzaHandler> getOutgoingPreStanzaHandlers() => [
|
||||||
|
StanzaHandler(
|
||||||
|
stanzaTag: 'message',
|
||||||
|
callback: _onMessageSent,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> onXmppEvent(XmppEvent event) async {
|
||||||
|
if (event is! StreamNegotiationsDoneEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only attempt rejoining if we did not resume the stream and all
|
||||||
|
// prepared rooms are already joined.
|
||||||
|
if (event.resumed && _joinedPreparedRooms) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _cacheLock.synchronized(() async {
|
||||||
|
// Mark all groupchats as not joined.
|
||||||
|
for (final jid in _mucRoomCache.keys) {
|
||||||
|
_mucRoomCache[jid]!.joined = false;
|
||||||
|
|
||||||
|
// Re-join all MUCs.
|
||||||
|
final state = _mucRoomCache[jid]!;
|
||||||
|
await _sendMucJoin(
|
||||||
|
jid,
|
||||||
|
state.nick!,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_joinedPreparedRooms = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Prepares the internal room list to ensure that the rooms
|
||||||
|
/// [rooms] are joined once we are connected.
|
||||||
|
Future<void> prepareRoomList(List<MUCRoomJoin> rooms) async {
|
||||||
|
assert(
|
||||||
|
rooms.isNotEmpty,
|
||||||
|
'The room list should not be empty',
|
||||||
|
);
|
||||||
|
|
||||||
|
await _cacheLock.synchronized(() {
|
||||||
|
_joinedPreparedRooms = false;
|
||||||
|
for (final room in rooms) {
|
||||||
|
final (roomJid, nick) = room;
|
||||||
|
_mucRoomCache[roomJid] = RoomState(
|
||||||
|
roomJid: roomJid,
|
||||||
|
nick: nick,
|
||||||
|
joined: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Queries the information of a Multi-User Chat room.
|
/// Queries the information of a Multi-User Chat room.
|
||||||
///
|
///
|
||||||
/// Retrieves the information about the specified MUC room by performing a
|
/// Retrieves the information about the specified MUC room by performing a
|
||||||
@ -55,11 +135,32 @@ class MUCManager extends XmppManagerBase {
|
|||||||
/// if applicable.
|
/// if applicable.
|
||||||
Future<Result<bool, MUCError>> joinRoom(
|
Future<Result<bool, MUCError>> joinRoom(
|
||||||
JID roomJid,
|
JID roomJid,
|
||||||
String nick,
|
String nick, {
|
||||||
) async {
|
int? maxHistoryStanzas,
|
||||||
|
}) async {
|
||||||
if (nick.isEmpty) {
|
if (nick.isEmpty) {
|
||||||
return Result(NoNicknameSpecified());
|
return Result(NoNicknameSpecified());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await _cacheLock.synchronized(
|
||||||
|
() {
|
||||||
|
_mucRoomCache[roomJid] = RoomState(
|
||||||
|
roomJid: roomJid,
|
||||||
|
nick: nick,
|
||||||
|
joined: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await _sendMucJoin(roomJid, nick, maxHistoryStanzas);
|
||||||
|
return const Result(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _sendMucJoin(
|
||||||
|
JID roomJid,
|
||||||
|
String nick,
|
||||||
|
int? maxHistoryStanzas,
|
||||||
|
) async {
|
||||||
await getAttributes().sendStanza(
|
await getAttributes().sendStanza(
|
||||||
StanzaDetails(
|
StanzaDetails(
|
||||||
Stanza.presence(
|
Stanza.presence(
|
||||||
@ -68,17 +169,20 @@ class MUCManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'x',
|
tag: 'x',
|
||||||
xmlns: mucXmlns,
|
xmlns: mucXmlns,
|
||||||
)
|
children: [
|
||||||
|
if (maxHistoryStanzas != null)
|
||||||
|
XMLNode(
|
||||||
|
tag: 'history',
|
||||||
|
attributes: {
|
||||||
|
'maxstanzas': maxHistoryStanzas.toString(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
await _cacheLock.synchronized(
|
|
||||||
() {
|
|
||||||
_mucRoomCache[roomJid] = RoomState(roomJid: roomJid, nick: nick);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return const Result(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Leaves a Multi-User Chat room.
|
/// Leaves a Multi-User Chat room.
|
||||||
@ -108,4 +212,86 @@ class MUCManager extends XmppManagerBase {
|
|||||||
);
|
);
|
||||||
return const Result(true);
|
return const Result(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<StanzaHandlerData> _onMessageSent(
|
||||||
|
Stanza message,
|
||||||
|
StanzaHandlerData state,
|
||||||
|
) async {
|
||||||
|
if (message.to == null) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
final toJid = JID.fromString(message.to!);
|
||||||
|
|
||||||
|
return _cacheLock.synchronized(() {
|
||||||
|
if (!_mucRoomCache.containsKey(toJid)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mucRoomCache[toJid]!.pendingMessages.add(
|
||||||
|
(message.id!, state.extensions.get<StableIdData>()?.originId),
|
||||||
|
);
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<StanzaHandlerData> _onMessage(
|
||||||
|
Stanza message,
|
||||||
|
StanzaHandlerData state,
|
||||||
|
) async {
|
||||||
|
final fromJid = JID.fromString(message.from!);
|
||||||
|
final roomJid = fromJid.toBare();
|
||||||
|
return _mucRoomCache.synchronized(() {
|
||||||
|
final roomState = _mucRoomCache[roomJid];
|
||||||
|
if (roomState == null) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type == 'groupchat' && message.firstTag('subject') != null) {
|
||||||
|
// The room subject marks the end of the join flow.
|
||||||
|
if (!roomState.joined) {
|
||||||
|
// Mark the room as joined.
|
||||||
|
_mucRoomCache[roomJid]!.joined = true;
|
||||||
|
logger.finest('$roomJid is now joined');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Unknown): Signal the subject?
|
||||||
|
|
||||||
|
return StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
message,
|
||||||
|
state.extensions,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (!roomState.joined) {
|
||||||
|
// Ignore the discussion history.
|
||||||
|
return StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
message,
|
||||||
|
state.extensions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is the message reflection.
|
||||||
|
final pending =
|
||||||
|
(message.id!, state.extensions.get<StableIdData>()?.originId);
|
||||||
|
if (fromJid.resource == roomState.nick &&
|
||||||
|
roomState.pendingMessages.contains(pending)) {
|
||||||
|
// Silently drop the message.
|
||||||
|
roomState.pendingMessages.remove(pending);
|
||||||
|
|
||||||
|
// TODO(Unknown): Maybe send an event stating that we received the reflection.
|
||||||
|
return StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
message,
|
||||||
|
state.extensions,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class VCardManager extends XmppManagerBase {
|
|||||||
tagName: 'x',
|
tagName: 'x',
|
||||||
tagXmlns: vCardTempUpdate,
|
tagXmlns: vCardTempUpdate,
|
||||||
callback: _onPresence,
|
callback: _onPresence,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -108,7 +108,7 @@ class VCardManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'vCard',
|
tag: 'vCard',
|
||||||
xmlns: vCardTempXmlns,
|
xmlns: vCardTempXmlns,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
encrypted: true,
|
encrypted: true,
|
||||||
|
@ -38,26 +38,20 @@ class PubSubPublishOptions {
|
|||||||
varAttr: 'FORM_TYPE',
|
varAttr: 'FORM_TYPE',
|
||||||
type: 'hidden',
|
type: 'hidden',
|
||||||
),
|
),
|
||||||
...accessModel != null
|
if (accessModel != null)
|
||||||
? [
|
|
||||||
DataFormField(
|
DataFormField(
|
||||||
options: [],
|
options: [],
|
||||||
isRequired: false,
|
isRequired: false,
|
||||||
values: [accessModel!],
|
values: [accessModel!],
|
||||||
varAttr: 'pubsub#access_model',
|
varAttr: 'pubsub#access_model',
|
||||||
)
|
),
|
||||||
]
|
if (maxItems != null)
|
||||||
: [],
|
|
||||||
...maxItems != null
|
|
||||||
? [
|
|
||||||
DataFormField(
|
DataFormField(
|
||||||
options: [],
|
options: [],
|
||||||
isRequired: false,
|
isRequired: false,
|
||||||
values: [maxItems!],
|
values: [maxItems!],
|
||||||
varAttr: 'pubsub#max_items',
|
varAttr: 'pubsub#max_items',
|
||||||
),
|
),
|
||||||
]
|
|
||||||
: [],
|
|
||||||
],
|
],
|
||||||
).toXml();
|
).toXml();
|
||||||
}
|
}
|
||||||
@ -87,7 +81,7 @@ class PubSubManager extends XmppManagerBase {
|
|||||||
tagName: 'event',
|
tagName: 'event',
|
||||||
tagXmlns: pubsubEventXmlns,
|
tagXmlns: pubsubEventXmlns,
|
||||||
callback: _onPubsubMessage,
|
callback: _onPubsubMessage,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -314,11 +308,11 @@ class PubSubManager extends XmppManagerBase {
|
|||||||
children: [
|
children: [
|
||||||
XMLNode(
|
XMLNode(
|
||||||
tag: 'item',
|
tag: 'item',
|
||||||
attributes: id != null
|
attributes: {
|
||||||
? <String, String>{'id': id}
|
if (id != null) 'id': id,
|
||||||
: <String, String>{},
|
},
|
||||||
children: [payload],
|
children: [payload],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (pubOptions != null)
|
if (pubOptions != null)
|
||||||
@ -327,7 +321,7 @@ class PubSubManager extends XmppManagerBase {
|
|||||||
children: [pubOptions.toXml()],
|
children: [pubOptions.toXml()],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
shouldEncrypt: false,
|
shouldEncrypt: false,
|
||||||
@ -422,7 +416,7 @@ class PubSubManager extends XmppManagerBase {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
shouldEncrypt: false,
|
shouldEncrypt: false,
|
||||||
|
@ -45,7 +45,7 @@ class OOBManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the message manager
|
// Before the message manager
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -69,7 +69,7 @@ class ChatStateManager extends XmppManagerBase {
|
|||||||
callback: _onChatStateReceived,
|
callback: _onChatStateReceived,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -66,7 +66,7 @@ class MessageDeliveryReceiptManager extends XmppManagerBase {
|
|||||||
callback: _onDeliveryRequestReceived,
|
callback: _onDeliveryRequestReceived,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -27,7 +27,7 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
tagName: 'block',
|
tagName: 'block',
|
||||||
tagXmlns: blockingXmlns,
|
tagXmlns: blockingXmlns,
|
||||||
callback: _blockPush,
|
callback: _blockPush,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -107,10 +107,12 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
children: items.map((item) {
|
children: items.map((item) {
|
||||||
return XMLNode(
|
return XMLNode(
|
||||||
tag: 'item',
|
tag: 'item',
|
||||||
attributes: <String, String>{'jid': item},
|
attributes: {
|
||||||
|
'jid': item,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -128,7 +130,7 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'unblock',
|
tag: 'unblock',
|
||||||
xmlns: blockingXmlns,
|
xmlns: blockingXmlns,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -152,11 +154,13 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
.map(
|
.map(
|
||||||
(item) => XMLNode(
|
(item) => XMLNode(
|
||||||
tag: 'item',
|
tag: 'item',
|
||||||
attributes: <String, String>{'jid': item},
|
attributes: {
|
||||||
|
'jid': item,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -174,7 +178,7 @@ class BlockingManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'blocklist',
|
tag: 'blocklist',
|
||||||
xmlns: blockingXmlns,
|
xmlns: blockingXmlns,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -5,7 +5,10 @@ class StreamManagementEnableNonza extends XMLNode {
|
|||||||
StreamManagementEnableNonza()
|
StreamManagementEnableNonza()
|
||||||
: super(
|
: super(
|
||||||
tag: 'enable',
|
tag: 'enable',
|
||||||
attributes: <String, String>{'xmlns': smXmlns, 'resume': 'true'},
|
attributes: {
|
||||||
|
'xmlns': smXmlns,
|
||||||
|
'resume': 'true',
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,10 +16,10 @@ class StreamManagementResumeNonza extends XMLNode {
|
|||||||
StreamManagementResumeNonza(String id, int h)
|
StreamManagementResumeNonza(String id, int h)
|
||||||
: super(
|
: super(
|
||||||
tag: 'resume',
|
tag: 'resume',
|
||||||
attributes: <String, String>{
|
attributes: {
|
||||||
'xmlns': smXmlns,
|
'xmlns': smXmlns,
|
||||||
'previd': id,
|
'previd': id,
|
||||||
'h': h.toString()
|
'h': h.toString(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -25,7 +28,10 @@ class StreamManagementAckNonza extends XMLNode {
|
|||||||
StreamManagementAckNonza(int h)
|
StreamManagementAckNonza(int h)
|
||||||
: super(
|
: super(
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: <String, String>{'xmlns': smXmlns, 'h': h.toString()},
|
attributes: {
|
||||||
|
'xmlns': smXmlns,
|
||||||
|
'h': h.toString(),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +39,7 @@ class StreamManagementRequestNonza extends XMLNode {
|
|||||||
StreamManagementRequestNonza()
|
StreamManagementRequestNonza()
|
||||||
: super(
|
: super(
|
||||||
tag: 'r',
|
tag: 'r',
|
||||||
attributes: <String, String>{
|
attributes: {
|
||||||
'xmlns': smXmlns,
|
'xmlns': smXmlns,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -140,7 +140,7 @@ class StreamManagementManager extends XmppManagerBase {
|
|||||||
nonzaTag: 'a',
|
nonzaTag: 'a',
|
||||||
nonzaXmlns: smXmlns,
|
nonzaXmlns: smXmlns,
|
||||||
callback: _handleAckResponse,
|
callback: _handleAckResponse,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -148,14 +148,14 @@ class StreamManagementManager extends XmppManagerBase {
|
|||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
callback: _onServerStanzaReceived,
|
callback: _onServerStanzaReceived,
|
||||||
priority: 9999,
|
priority: 9999,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<StanzaHandler> getOutgoingPostStanzaHandlers() => [
|
List<StanzaHandler> getOutgoingPostStanzaHandlers() => [
|
||||||
StanzaHandler(
|
StanzaHandler(
|
||||||
callback: _onClientStanzaSent,
|
callback: _onClientStanzaSent,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -49,7 +49,7 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
tagXmlns: carbonsXmlns,
|
tagXmlns: carbonsXmlns,
|
||||||
callback: _onMessageSent,
|
callback: _onMessageSent,
|
||||||
priority: -98,
|
priority: -98,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -124,7 +124,7 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'enable',
|
tag: 'enable',
|
||||||
xmlns: carbonsXmlns,
|
xmlns: carbonsXmlns,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -154,7 +154,7 @@ class CarbonsManager extends XmppManagerBase {
|
|||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'disable',
|
tag: 'disable',
|
||||||
xmlns: carbonsXmlns,
|
xmlns: carbonsXmlns,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -40,7 +40,7 @@ class LastMessageCorrectionManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -100,7 +100,7 @@ class ChatMarkerManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -81,7 +81,7 @@ class StableIdManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the MessageManager
|
// Before the MessageManager
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -127,7 +127,13 @@ class StableIdManager extends XmppManagerBase {
|
|||||||
TypedMap<StanzaHandlerExtension> extensions,
|
TypedMap<StanzaHandlerExtension> extensions,
|
||||||
) {
|
) {
|
||||||
final data = extensions.get<StableIdData>();
|
final data = extensions.get<StableIdData>();
|
||||||
return data != null ? data.toXML() : [];
|
if (data?.originId != null) {
|
||||||
|
return [
|
||||||
|
data!.toOriginIdElement(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -161,9 +161,9 @@ class HttpFileUploadManager extends XmppManagerBase {
|
|||||||
attributes: {
|
attributes: {
|
||||||
'filename': filename,
|
'filename': filename,
|
||||||
'size': filesize.toString(),
|
'size': filesize.toString(),
|
||||||
...contentType != null ? {'content-type': contentType} : {}
|
if (contentType != null) 'content-type': contentType,
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -2,10 +2,10 @@ abstract class OmemoError {}
|
|||||||
|
|
||||||
class UnknownOmemoError extends OmemoError {}
|
class UnknownOmemoError extends OmemoError {}
|
||||||
|
|
||||||
class InvalidAffixElementsException with Exception {}
|
class InvalidAffixElementsException implements Exception {}
|
||||||
|
|
||||||
class OmemoNotSupportedForContactException extends OmemoError {}
|
class OmemoNotSupportedForContactException extends OmemoError {}
|
||||||
|
|
||||||
class EncryptionFailedException with Exception {}
|
class EncryptionFailedException implements Exception {}
|
||||||
|
|
||||||
class InvalidEnvelopePayloadException with Exception {}
|
class InvalidEnvelopePayloadException implements Exception {}
|
||||||
|
@ -82,7 +82,7 @@ class SIMSManager extends XmppManagerBase {
|
|||||||
tagXmlns: referenceXmlns,
|
tagXmlns: referenceXmlns,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -31,7 +31,7 @@ class MessageRetractionManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the MessageManager
|
// Before the MessageManager
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -133,7 +133,7 @@ class SFSManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -98,
|
priority: -98,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -96,7 +96,7 @@ class MessageRepliesManager extends XmppManagerBase {
|
|||||||
callback: _onMessage,
|
callback: _onMessage,
|
||||||
// Before the message handler
|
// Before the message handler
|
||||||
priority: -99,
|
priority: -99,
|
||||||
)
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -5,7 +5,7 @@ homepage: https://codeberg.org/moxxy/moxxmpp
|
|||||||
publish_to: https://git.polynom.me/api/packages/Moxxy/pub
|
publish_to: https://git.polynom.me/api/packages/Moxxy/pub
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.17.5 <3.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
collection: ^1.16.0
|
collection: ^1.16.0
|
||||||
|
@ -14,9 +14,9 @@ final scramSha1StreamFeatures = XMLNode(
|
|||||||
XMLNode(
|
XMLNode(
|
||||||
tag: 'mechanism',
|
tag: 'mechanism',
|
||||||
text: 'SCRAM-SHA-1',
|
text: 'SCRAM-SHA-1',
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
final scramSha256StreamFeatures = XMLNode(
|
final scramSha256StreamFeatures = XMLNode(
|
||||||
@ -29,9 +29,9 @@ final scramSha256StreamFeatures = XMLNode(
|
|||||||
XMLNode(
|
XMLNode(
|
||||||
tag: 'mechanism',
|
tag: 'mechanism',
|
||||||
text: 'SCRAM-SHA-256',
|
text: 'SCRAM-SHA-256',
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
tagName: '3',
|
tagName: '3',
|
||||||
priority: 50,
|
priority: 50,
|
||||||
)
|
),
|
||||||
]..sort(stanzaHandlerSortComparator);
|
]..sort(stanzaHandlerSortComparator);
|
||||||
|
|
||||||
expect(handlerList[0].tagName, '1');
|
expect(handlerList[0].tagName, '1');
|
||||||
|
@ -158,7 +158,7 @@ void main() {
|
|||||||
</iq>''',
|
</iq>''',
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
adjustId: true,
|
adjustId: true,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class StubbedDiscoManager extends DiscoManager {
|
|||||||
isRequired: false,
|
isRequired: false,
|
||||||
varAttr: 'FORM_TYPE',
|
varAttr: 'FORM_TYPE',
|
||||||
type: 'hidden',
|
type: 'hidden',
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
reported: [],
|
reported: [],
|
||||||
items: [],
|
items: [],
|
||||||
@ -153,14 +153,14 @@ void main() {
|
|||||||
'http://jabber.org/protocol/caps',
|
'http://jabber.org/protocol/caps',
|
||||||
'http://jabber.org/protocol/disco#info',
|
'http://jabber.org/protocol/disco#info',
|
||||||
'http://jabber.org/protocol/disco#items',
|
'http://jabber.org/protocol/disco#items',
|
||||||
'http://jabber.org/protocol/muc'
|
'http://jabber.org/protocol/muc',
|
||||||
],
|
],
|
||||||
const [
|
const [
|
||||||
Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'pc',
|
type: 'pc',
|
||||||
name: 'Exodus 0.9.1',
|
name: 'Exodus 0.9.1',
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
const [],
|
const [],
|
||||||
null,
|
null,
|
||||||
@ -179,7 +179,7 @@ void main() {
|
|||||||
'http://jabber.org/protocol/caps',
|
'http://jabber.org/protocol/caps',
|
||||||
'http://jabber.org/protocol/disco#info',
|
'http://jabber.org/protocol/disco#info',
|
||||||
'http://jabber.org/protocol/disco#items',
|
'http://jabber.org/protocol/disco#items',
|
||||||
'http://jabber.org/protocol/muc'
|
'http://jabber.org/protocol/muc',
|
||||||
],
|
],
|
||||||
const [
|
const [
|
||||||
Identity(
|
Identity(
|
||||||
@ -295,14 +295,14 @@ void main() {
|
|||||||
'urn:xmpp:message-correct:0',
|
'urn:xmpp:message-correct:0',
|
||||||
'urn:xmpp:ping',
|
'urn:xmpp:ping',
|
||||||
'urn:xmpp:receipts',
|
'urn:xmpp:receipts',
|
||||||
'urn:xmpp:time'
|
'urn:xmpp:time',
|
||||||
],
|
],
|
||||||
const [
|
const [
|
||||||
Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'phone',
|
type: 'phone',
|
||||||
name: 'Conversations',
|
name: 'Conversations',
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
const [],
|
const [],
|
||||||
null,
|
null,
|
||||||
|
@ -433,7 +433,8 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Test a failed stream resumption', () async {
|
test('Test a failed stream resumption', () async {
|
||||||
final fakeSocket = StubTCPSocket([
|
final fakeSocket = StubTCPSocket(
|
||||||
|
[
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' from='polynomdivision@test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' from='polynomdivision@test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
@ -486,8 +487,9 @@ void main() {
|
|||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
'<enabled xmlns="urn:xmpp:sm:3" id="id-2" resume="true" />',
|
'<enabled xmlns="urn:xmpp:sm:3" id="id-2" resume="true" />',
|
||||||
)
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
final conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
|
@ -115,7 +115,8 @@ void main() {
|
|||||||
test('Test sending a message processing hint', () async {
|
test('Test sending a message processing hint', () async {
|
||||||
final manager = MessageManager();
|
final manager = MessageManager();
|
||||||
final holder = TestingManagerHolder(
|
final holder = TestingManagerHolder(
|
||||||
stubSocket: StubTCPSocket([
|
stubSocket: StubTCPSocket(
|
||||||
|
[
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'''
|
'''
|
||||||
<message to="user@example.org" type="chat">
|
<message to="user@example.org" type="chat">
|
||||||
@ -124,8 +125,9 @@ void main() {
|
|||||||
</message>
|
</message>
|
||||||
''',
|
''',
|
||||||
'',
|
'',
|
||||||
)
|
),
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
await holder.register([
|
await holder.register([
|
||||||
|
@ -6,7 +6,7 @@ void main() {
|
|||||||
test('invariance', () {
|
test('invariance', () {
|
||||||
final headers = {
|
final headers = {
|
||||||
'authorization': 'Basic Base64String==',
|
'authorization': 'Basic Base64String==',
|
||||||
'cookie': 'foo=bar; user=romeo'
|
'cookie': 'foo=bar; user=romeo',
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
prepareHeaders(headers),
|
prepareHeaders(headers),
|
||||||
@ -16,7 +16,7 @@ void main() {
|
|||||||
test('invariance through uppercase', () {
|
test('invariance through uppercase', () {
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': 'Basic Base64String==',
|
'Authorization': 'Basic Base64String==',
|
||||||
'Cookie': 'foo=bar; user=romeo'
|
'Cookie': 'foo=bar; user=romeo',
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
prepareHeaders(headers),
|
prepareHeaders(headers),
|
||||||
@ -27,7 +27,7 @@ void main() {
|
|||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': 'Basic Base64String==',
|
'Authorization': 'Basic Base64String==',
|
||||||
'Cookie': 'foo=bar; user=romeo',
|
'Cookie': 'foo=bar; user=romeo',
|
||||||
'X-Tracking': 'Base64String=='
|
'X-Tracking': 'Base64String==',
|
||||||
};
|
};
|
||||||
expect(prepareHeaders(headers), {
|
expect(prepareHeaders(headers), {
|
||||||
'Authorization': 'Basic Base64String==',
|
'Authorization': 'Basic Base64String==',
|
||||||
|
Loading…
Reference in New Issue
Block a user