|
@@ -11,12 +11,23 @@ import ChatRoomMixin from './muc.js';
|
|
import ChatRoomOccupant from './occupant.js';
|
|
import ChatRoomOccupant from './occupant.js';
|
|
import ChatRoomOccupants from './occupants.js';
|
|
import ChatRoomOccupants from './occupants.js';
|
|
import affiliations_api from './affiliations/api.js';
|
|
import affiliations_api from './affiliations/api.js';
|
|
-import isObject from 'lodash-es/isObject';
|
|
|
|
-import log from '@converse/headless/log';
|
|
|
|
import muc_api from './api.js';
|
|
import muc_api from './api.js';
|
|
-import u from '../../utils/form';
|
|
|
|
import { Collection } from '@converse/skeletor/src/collection';
|
|
import { Collection } from '@converse/skeletor/src/collection';
|
|
import { _converse, api, converse } from '../../core.js';
|
|
import { _converse, api, converse } from '../../core.js';
|
|
|
|
+import {
|
|
|
|
+ autoJoinRooms,
|
|
|
|
+ disconnectChatRooms,
|
|
|
|
+ getDefaultMUCNickname,
|
|
|
|
+ isInfoVisible,
|
|
|
|
+ onAddClientFeatures,
|
|
|
|
+ onBeforeResourceBinding,
|
|
|
|
+ onBeforeTearDown,
|
|
|
|
+ onDirectMUCInvitation,
|
|
|
|
+ onStatusInitialized,
|
|
|
|
+ onWindowStateChanged,
|
|
|
|
+ registerDirectInvitationHandler,
|
|
|
|
+ routeToRoom,
|
|
|
|
+} from './utils.js';
|
|
import { computeAffiliationsDelta } from './affiliations/utils.js';
|
|
import { computeAffiliationsDelta } from './affiliations/utils.js';
|
|
|
|
|
|
export const ROLES = ['moderator', 'participant', 'visitor'];
|
|
export const ROLES = ['moderator', 'participant', 'visitor'];
|
|
@@ -29,7 +40,7 @@ converse.AFFILIATION_CHANGES = {
|
|
EXADMIN: 'exadmin',
|
|
EXADMIN: 'exadmin',
|
|
EXOWNER: 'exowner',
|
|
EXOWNER: 'exowner',
|
|
EXOUTCAST: 'exoutcast',
|
|
EXOUTCAST: 'exoutcast',
|
|
- EXMEMBER: 'exmember'
|
|
|
|
|
|
+ EXMEMBER: 'exmember',
|
|
};
|
|
};
|
|
converse.AFFILIATION_CHANGES_LIST = Object.values(converse.AFFILIATION_CHANGES);
|
|
converse.AFFILIATION_CHANGES_LIST = Object.values(converse.AFFILIATION_CHANGES);
|
|
converse.MUC_TRAFFIC_STATES = { ENTERED: 'entered', EXITED: 'exited' };
|
|
converse.MUC_TRAFFIC_STATES = { ENTERED: 'entered', EXITED: 'exited' };
|
|
@@ -48,10 +59,10 @@ converse.MUC.INFO_CODES = {
|
|
'disconnected': ['301', '307', '321', '322', '332', '333'],
|
|
'disconnected': ['301', '307', '321', '322', '332', '333'],
|
|
'affiliation_changes': [...converse.AFFILIATION_CHANGES_LIST],
|
|
'affiliation_changes': [...converse.AFFILIATION_CHANGES_LIST],
|
|
'join_leave_events': [...converse.MUC_TRAFFIC_STATES_LIST],
|
|
'join_leave_events': [...converse.MUC_TRAFFIC_STATES_LIST],
|
|
- 'role_changes': [...converse.MUC_ROLE_CHANGES_LIST]
|
|
|
|
|
|
+ 'role_changes': [...converse.MUC_ROLE_CHANGES_LIST],
|
|
};
|
|
};
|
|
|
|
|
|
-const { Strophe, sizzle } = converse.env;
|
|
|
|
|
|
+const { Strophe } = converse.env;
|
|
|
|
|
|
// Add Strophe Namespaces
|
|
// Add Strophe Namespaces
|
|
Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + '#admin');
|
|
Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + '#admin');
|
|
@@ -60,6 +71,7 @@ Strophe.addNamespace('MUC_REGISTER', 'jabber:iq:register');
|
|
Strophe.addNamespace('MUC_ROOMCONF', Strophe.NS.MUC + '#roomconfig');
|
|
Strophe.addNamespace('MUC_ROOMCONF', Strophe.NS.MUC + '#roomconfig');
|
|
Strophe.addNamespace('MUC_USER', Strophe.NS.MUC + '#user');
|
|
Strophe.addNamespace('MUC_USER', Strophe.NS.MUC + '#user');
|
|
Strophe.addNamespace('MUC_HATS', 'xmpp:prosody.im/protocol/hats:1');
|
|
Strophe.addNamespace('MUC_HATS', 'xmpp:prosody.im/protocol/hats:1');
|
|
|
|
+Strophe.addNamespace('CONFINFO', 'urn:ietf:params:xml:ns:conference-info');
|
|
|
|
|
|
converse.MUC_NICK_CHANGED_CODE = '303';
|
|
converse.MUC_NICK_CHANGED_CODE = '303';
|
|
|
|
|
|
@@ -76,7 +88,7 @@ converse.ROOM_FEATURES = [
|
|
'semianonymous',
|
|
'semianonymous',
|
|
'moderated',
|
|
'moderated',
|
|
'unmoderated',
|
|
'unmoderated',
|
|
- 'mam_enabled'
|
|
|
|
|
|
+ 'mam_enabled',
|
|
];
|
|
];
|
|
|
|
|
|
// No longer used in code, but useful as reference.
|
|
// No longer used in code, but useful as reference.
|
|
@@ -104,92 +116,9 @@ converse.ROOMSTATUS = {
|
|
DISCONNECTED: 4,
|
|
DISCONNECTED: 4,
|
|
ENTERED: 5,
|
|
ENTERED: 5,
|
|
DESTROYED: 6,
|
|
DESTROYED: 6,
|
|
- BANNED: 7
|
|
|
|
|
|
+ BANNED: 7,
|
|
};
|
|
};
|
|
|
|
|
|
-
|
|
|
|
-function registerDirectInvitationHandler () {
|
|
|
|
- _converse.connection.addHandler(
|
|
|
|
- message => {
|
|
|
|
- _converse.onDirectMUCInvitation(message);
|
|
|
|
- return true;
|
|
|
|
- },
|
|
|
|
- 'jabber:x:conference',
|
|
|
|
- 'message'
|
|
|
|
- );
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function disconnectChatRooms () {
|
|
|
|
- /* When disconnecting, mark all groupchats as
|
|
|
|
- * disconnected, so that they will be properly entered again
|
|
|
|
- * when fetched from session storage.
|
|
|
|
- */
|
|
|
|
- return _converse.chatboxes
|
|
|
|
- .filter(m => m.get('type') === _converse.CHATROOMS_TYPE)
|
|
|
|
- .forEach(m => m.session.save({ 'connection_status': converse.ROOMSTATUS.DISCONNECTED }));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-async function onWindowStateChanged (data) {
|
|
|
|
- if (data.state === 'visible' && api.connection.connected()) {
|
|
|
|
- const rooms = await api.rooms.get();
|
|
|
|
- rooms.forEach(room => room.rejoinIfNecessary());
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-async function routeToRoom (jid) {
|
|
|
|
- if (!u.isValidMUCJID(jid)) {
|
|
|
|
- return log.warn(`invalid jid "${jid}" provided in url fragment`);
|
|
|
|
- }
|
|
|
|
- await api.waitUntil('roomsAutoJoined');
|
|
|
|
- if (api.settings.get('allow_bookmarks')) {
|
|
|
|
- await api.waitUntil('bookmarksInitialized');
|
|
|
|
- }
|
|
|
|
- api.rooms.open(jid);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Opens a groupchat, making sure that certain attributes
|
|
|
|
- * are correct, for example that the "type" is set to
|
|
|
|
- * "chatroom".
|
|
|
|
- */
|
|
|
|
-async function openChatRoom (jid, settings) {
|
|
|
|
- settings.type = _converse.CHATROOMS_TYPE;
|
|
|
|
- settings.id = jid;
|
|
|
|
- const chatbox = await api.rooms.get(jid, settings, true);
|
|
|
|
- chatbox.maybeShow(true);
|
|
|
|
- return chatbox;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* Automatically join groupchats, based on the
|
|
|
|
- * "auto_join_rooms" configuration setting, which is an array
|
|
|
|
- * of strings (groupchat JIDs) or objects (with groupchat JID and other settings).
|
|
|
|
- */
|
|
|
|
-async function autoJoinRooms () {
|
|
|
|
- await Promise.all(
|
|
|
|
- api.settings.get('auto_join_rooms').map(muc => {
|
|
|
|
- if (typeof muc === 'string') {
|
|
|
|
- if (_converse.chatboxes.where({ 'jid': muc }).length) {
|
|
|
|
- return Promise.resolve();
|
|
|
|
- }
|
|
|
|
- return api.rooms.open(muc);
|
|
|
|
- } else if (isObject(muc)) {
|
|
|
|
- return api.rooms.open(muc.jid, { ...muc });
|
|
|
|
- } else {
|
|
|
|
- log.error('Invalid muc criteria specified for "auto_join_rooms"');
|
|
|
|
- return Promise.resolve();
|
|
|
|
- }
|
|
|
|
- })
|
|
|
|
- );
|
|
|
|
- /**
|
|
|
|
- * Triggered once any rooms that have been configured to be automatically joined,
|
|
|
|
- * specified via the _`auto_join_rooms` setting, have been entered.
|
|
|
|
- * @event _converse#roomsAutoJoined
|
|
|
|
- * @example _converse.api.listen.on('roomsAutoJoined', () => { ... });
|
|
|
|
- * @example _converse.api.waitUntil('roomsAutoJoined').then(() => { ... });
|
|
|
|
- */
|
|
|
|
- api.trigger('roomsAutoJoined');
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-
|
|
|
|
converse.plugins.add('converse-muc', {
|
|
converse.plugins.add('converse-muc', {
|
|
/* Optional dependencies are other plugins which might be
|
|
/* Optional dependencies are other plugins which might be
|
|
* overridden or relied upon, and therefore need to be loaded before
|
|
* overridden or relied upon, and therefore need to be loaded before
|
|
@@ -214,8 +143,8 @@ converse.plugins.add('converse-muc', {
|
|
} else {
|
|
} else {
|
|
return this.__super__.model.apply(this, arguments);
|
|
return this.__super__.model.apply(this, arguments);
|
|
}
|
|
}
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ },
|
|
|
|
+ },
|
|
},
|
|
},
|
|
|
|
|
|
initialize () {
|
|
initialize () {
|
|
@@ -253,7 +182,7 @@ converse.plugins.add('converse-muc', {
|
|
...converse.MUC.INFO_CODES.disconnected,
|
|
...converse.MUC.INFO_CODES.disconnected,
|
|
...converse.MUC.INFO_CODES.affiliation_changes,
|
|
...converse.MUC.INFO_CODES.affiliation_changes,
|
|
...converse.MUC.INFO_CODES.join_leave_events,
|
|
...converse.MUC.INFO_CODES.join_leave_events,
|
|
- ...converse.MUC.INFO_CODES.role_changes
|
|
|
|
|
|
+ ...converse.MUC.INFO_CODES.role_changes,
|
|
],
|
|
],
|
|
'muc_show_logs_before_join': false,
|
|
'muc_show_logs_before_join': false,
|
|
'muc_show_ogp_unfurls': true,
|
|
'muc_show_ogp_unfurls': true,
|
|
@@ -305,13 +234,13 @@ converse.plugins.add('converse-muc', {
|
|
172: __('This groupchat is now no longer anonymous'),
|
|
172: __('This groupchat is now no longer anonymous'),
|
|
173: __('This groupchat is now semi-anonymous'),
|
|
173: __('This groupchat is now semi-anonymous'),
|
|
174: __('This groupchat is now fully-anonymous'),
|
|
174: __('This groupchat is now fully-anonymous'),
|
|
- 201: __('A new groupchat has been created')
|
|
|
|
|
|
+ 201: __('A new groupchat has been created'),
|
|
},
|
|
},
|
|
|
|
|
|
new_nickname_messages: {
|
|
new_nickname_messages: {
|
|
// XXX: Note the triple underscore function and not double underscore.
|
|
// XXX: Note the triple underscore function and not double underscore.
|
|
210: ___('Your nickname has been automatically set to %1$s'),
|
|
210: ___('Your nickname has been automatically set to %1$s'),
|
|
- 303: ___('Your nickname has been changed to %1$s')
|
|
|
|
|
|
+ 303: ___('Your nickname has been changed to %1$s'),
|
|
},
|
|
},
|
|
|
|
|
|
disconnect_messages: {
|
|
disconnect_messages: {
|
|
@@ -322,22 +251,8 @@ converse.plugins.add('converse-muc', {
|
|
322: __(
|
|
322: __(
|
|
"You have been removed from this groupchat because the groupchat has changed to members-only and you're not a member"
|
|
"You have been removed from this groupchat because the groupchat has changed to members-only and you're not a member"
|
|
),
|
|
),
|
|
- 332: __('You have been removed from this groupchat because the service hosting it is being shut down')
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Determines info message visibility based on
|
|
|
|
- * muc_show_info_messages configuration setting
|
|
|
|
- * @param {*} code
|
|
|
|
- * @memberOf _converse
|
|
|
|
- */
|
|
|
|
- _converse.isInfoVisible = function (code) {
|
|
|
|
- const info_messages = api.settings.get('muc_show_info_messages');
|
|
|
|
- if (info_messages.includes(code)) {
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- return false;
|
|
|
|
|
|
+ 332: __('You have been removed from this groupchat because the service hosting it is being shut down'),
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
_converse.router.route('converse/room?jid=:jid', routeToRoom);
|
|
_converse.router.route('converse/room?jid=:jid', routeToRoom);
|
|
@@ -347,22 +262,6 @@ converse.plugins.add('converse-muc', {
|
|
_converse.ChatRoomOccupants = ChatRoomOccupants;
|
|
_converse.ChatRoomOccupants = ChatRoomOccupants;
|
|
_converse.ChatRoomOccupant = ChatRoomOccupant;
|
|
_converse.ChatRoomOccupant = ChatRoomOccupant;
|
|
|
|
|
|
- _converse.getDefaultMUCNickname = function () {
|
|
|
|
- // XXX: if anything changes here, update the docs for the
|
|
|
|
- // locked_muc_nickname setting.
|
|
|
|
- if (!_converse.xmppstatus) {
|
|
|
|
- throw new Error(
|
|
|
|
- "Can't call _converse.getDefaultMUCNickname before the statusInitialized has been fired."
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- const nick = _converse.xmppstatus.getNickname();
|
|
|
|
- if (nick) {
|
|
|
|
- return nick;
|
|
|
|
- } else if (api.settings.get('muc_nickname_from_jid')) {
|
|
|
|
- return Strophe.unescapeNode(Strophe.getNodeFromJid(_converse.bare_jid));
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Collection which stores MUC messages
|
|
* Collection which stores MUC messages
|
|
* @class
|
|
* @class
|
|
@@ -371,113 +270,23 @@ converse.plugins.add('converse-muc', {
|
|
*/
|
|
*/
|
|
_converse.ChatRoomMessages = Collection.extend({
|
|
_converse.ChatRoomMessages = Collection.extend({
|
|
model: _converse.ChatRoomMessage,
|
|
model: _converse.ChatRoomMessage,
|
|
- comparator: 'time'
|
|
|
|
|
|
+ comparator: 'time',
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+ Object.assign(_converse, { getDefaultMUCNickname, isInfoVisible, onDirectMUCInvitation });
|
|
|
|
|
|
- /**
|
|
|
|
- * A direct MUC invitation to join a groupchat has been received
|
|
|
|
- * See XEP-0249: Direct MUC invitations.
|
|
|
|
- * @private
|
|
|
|
- * @method _converse.ChatRoom#onDirectMUCInvitation
|
|
|
|
- * @param { XMLElement } message - The message stanza containing the invitation.
|
|
|
|
- */
|
|
|
|
- _converse.onDirectMUCInvitation = async function (message) {
|
|
|
|
- const x_el = sizzle('x[xmlns="jabber:x:conference"]', message).pop(),
|
|
|
|
- from = Strophe.getBareJidFromJid(message.getAttribute('from')),
|
|
|
|
- room_jid = x_el.getAttribute('jid'),
|
|
|
|
- reason = x_el.getAttribute('reason');
|
|
|
|
-
|
|
|
|
- let result;
|
|
|
|
- if (api.settings.get('auto_join_on_invite')) {
|
|
|
|
- result = true;
|
|
|
|
- } else {
|
|
|
|
- // Invite request might come from someone not your roster list
|
|
|
|
- let contact = _converse.roster.get(from);
|
|
|
|
- contact = contact ? contact.getDisplayName() : from;
|
|
|
|
- if (!reason) {
|
|
|
|
- result = confirm(__('%1$s has invited you to join a groupchat: %2$s', contact, room_jid));
|
|
|
|
- } else {
|
|
|
|
- result = confirm(
|
|
|
|
- __(
|
|
|
|
- '%1$s has invited you to join a groupchat: %2$s, and left the following reason: "%3$s"',
|
|
|
|
- contact,
|
|
|
|
- room_jid,
|
|
|
|
- reason
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (result === true) {
|
|
|
|
- const chatroom = await openChatRoom(room_jid, { 'password': x_el.getAttribute('password') });
|
|
|
|
- if (chatroom.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED) {
|
|
|
|
- _converse.chatboxes.get(room_jid).rejoin();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
|
|
/************************ BEGIN Event Handlers ************************/
|
|
/************************ BEGIN Event Handlers ************************/
|
|
-
|
|
|
|
if (api.settings.get('allow_muc_invitations')) {
|
|
if (api.settings.get('allow_muc_invitations')) {
|
|
api.listen.on('connected', registerDirectInvitationHandler);
|
|
api.listen.on('connected', registerDirectInvitationHandler);
|
|
api.listen.on('reconnected', registerDirectInvitationHandler);
|
|
api.listen.on('reconnected', registerDirectInvitationHandler);
|
|
}
|
|
}
|
|
-
|
|
|
|
- api.listen.on('beforeTearDown', () => {
|
|
|
|
- const groupchats = _converse.chatboxes.where({ 'type': _converse.CHATROOMS_TYPE });
|
|
|
|
- groupchats.forEach(muc =>
|
|
|
|
- u.safeSave(muc.session, { 'connection_status': converse.ROOMSTATUS.DISCONNECTED })
|
|
|
|
- );
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- api.listen.on('windowStateChanged', onWindowStateChanged);
|
|
|
|
-
|
|
|
|
- api.listen.on('addClientFeatures', () => {
|
|
|
|
- if (api.settings.get('allow_muc')) {
|
|
|
|
- api.disco.own.features.add(Strophe.NS.MUC);
|
|
|
|
- }
|
|
|
|
- if (api.settings.get('allow_muc_invitations')) {
|
|
|
|
- api.disco.own.features.add('jabber:x:conference'); // Invites
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+ api.listen.on('addClientFeatures', onAddClientFeatures);
|
|
|
|
+ api.listen.on('beforeResourceBinding', onBeforeResourceBinding);
|
|
|
|
+ api.listen.on('beforeTearDown', onBeforeTearDown);
|
|
api.listen.on('chatBoxesFetched', autoJoinRooms);
|
|
api.listen.on('chatBoxesFetched', autoJoinRooms);
|
|
-
|
|
|
|
- api.listen.on('beforeResourceBinding', () => {
|
|
|
|
- _converse.connection.addHandler(
|
|
|
|
- stanza => {
|
|
|
|
- const muc_jid = Strophe.getBareJidFromJid(stanza.getAttribute('from'));
|
|
|
|
- if (!_converse.chatboxes.get(muc_jid)) {
|
|
|
|
- api.waitUntil('chatBoxesFetched').then(async () => {
|
|
|
|
- const muc = _converse.chatboxes.get(muc_jid);
|
|
|
|
- if (muc) {
|
|
|
|
- await muc.initialized;
|
|
|
|
- muc.message_handler.run(stanza);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- return true;
|
|
|
|
- },
|
|
|
|
- null,
|
|
|
|
- 'message',
|
|
|
|
- 'groupchat'
|
|
|
|
- );
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
api.listen.on('disconnected', disconnectChatRooms);
|
|
api.listen.on('disconnected', disconnectChatRooms);
|
|
-
|
|
|
|
- api.listen.on('statusInitialized', () => {
|
|
|
|
- window.addEventListener(_converse.unloadevent, () => {
|
|
|
|
- const using_websocket = api.connection.isType('websocket');
|
|
|
|
- if (
|
|
|
|
- using_websocket &&
|
|
|
|
- (!api.settings.get('enable_smacks') || !_converse.session.get('smacks_stream_id'))
|
|
|
|
- ) {
|
|
|
|
- // For non-SMACKS websocket connections, or non-resumeable
|
|
|
|
- // connections, we disconnect all chatrooms when the page unloads.
|
|
|
|
- // See issue #1111
|
|
|
|
- disconnectChatRooms();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
|
|
+ api.listen.on('statusInitialized', onStatusInitialized);
|
|
|
|
+ api.listen.on('windowStateChanged', onWindowStateChanged);
|
|
|
|
+ },
|
|
});
|
|
});
|