Add a plugin for XEP-0357
Currently only allows enabling an "App Service", based on pass-in configuration values.
This commit is contained in:
parent
eed141b53e
commit
7ee71b0132
|
@ -9,6 +9,7 @@
|
||||||
"plugins": ["lodash"],
|
"plugins": ["lodash"],
|
||||||
"extends": ["eslint:recommended", "plugin:lodash/canonical"],
|
"extends": ["eslint:recommended", "plugin:lodash/canonical"],
|
||||||
"globals": {
|
"globals": {
|
||||||
|
"Promise": true,
|
||||||
"converse": true,
|
"converse": true,
|
||||||
"window": true,
|
"window": true,
|
||||||
"sinon": true,
|
"sinon": true,
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
- Add a checkbox to indicate whether a trusted device is being used or not.
|
- Add a checkbox to indicate whether a trusted device is being used or not.
|
||||||
If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout.
|
If the device is not trusted, sessionStorage is used and all user data is deleted from the browser cache upon logout.
|
||||||
If the device is trusted, localStorage is used and user data is cached indefinitely.
|
If the device is trusted, localStorage is used and user data is cached indefinitely.
|
||||||
|
- Initial support for XEP-0357 Push Notifications, specifically registering an "App Server".
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
||||||
|
|
113
dist/converse.js
vendored
113
dist/converse.js
vendored
|
@ -64922,11 +64922,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
|
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
|
||||||
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||||||
})(void 0, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
|
})(void 0, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
|
||||||
/* Cannot use this due to Safari bug.
|
"use strict"; // Strophe globals
|
||||||
* See https://github.com/jcbrand/converse.js/issues/196
|
|
||||||
*/
|
|
||||||
// "use strict";
|
|
||||||
// Strophe globals
|
|
||||||
const _Strophe = Strophe,
|
const _Strophe = Strophe,
|
||||||
$build = _Strophe.$build,
|
$build = _Strophe.$build,
|
||||||
$iq = _Strophe.$iq,
|
$iq = _Strophe.$iq,
|
||||||
|
@ -64974,7 +64971,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
_.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically
|
_.extend(_converse, Backbone.Events); // Core plugins are whitelisted automatically
|
||||||
|
|
||||||
|
|
||||||
_converse.core_plugins = ['converse-bookmarks', 'converse-chatboxes', 'converse-chatview', 'converse-caps', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-otr', 'converse-ping', 'converse-profile', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Make converse pluggable
|
_converse.core_plugins = ['converse-bookmarks', 'converse-caps', 'converse-chatboxes', 'converse-chatview', 'converse-controlbox', 'converse-core', 'converse-disco', 'converse-dragresize', 'converse-embedded', 'converse-fullscreen', 'converse-headline', 'converse-mam', 'converse-message-view', 'converse-minimize', 'converse-modal', 'converse-muc', 'converse-muc-views', 'converse-notification', 'converse-ping', 'converse-profile', 'converse-push', 'converse-register', 'converse-roomslist', 'converse-roster', 'converse-rosterview', 'converse-singleton', 'converse-spoilers', 'converse-vcard']; // Make converse pluggable
|
||||||
|
|
||||||
pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants
|
pluggable.enable(_converse, '_converse', 'pluggable'); // Module-level constants
|
||||||
|
|
||||||
|
@ -65004,6 +65001,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
_converse.LOGOUT = "logout";
|
_converse.LOGOUT = "logout";
|
||||||
_converse.OPENED = 'opened';
|
_converse.OPENED = 'opened';
|
||||||
_converse.PREBIND = "prebind";
|
_converse.PREBIND = "prebind";
|
||||||
|
_converse.IQ_TIMEOUT = 30000;
|
||||||
_converse.CONNECTION_STATUS = {
|
_converse.CONNECTION_STATUS = {
|
||||||
0: 'ERROR',
|
0: 'ERROR',
|
||||||
1: 'CONNECTING',
|
1: 'CONNECTING',
|
||||||
|
@ -65173,8 +65171,6 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
_converse.router = new Backbone.Router();
|
_converse.router = new Backbone.Router();
|
||||||
|
|
||||||
_converse.initialize = function (settings, callback) {
|
_converse.initialize = function (settings, callback) {
|
||||||
"use strict";
|
|
||||||
|
|
||||||
settings = !_.isUndefined(settings) ? settings : {};
|
settings = !_.isUndefined(settings) ? settings : {};
|
||||||
const init_promise = u.getResolveablePromise();
|
const init_promise = u.getResolveablePromise();
|
||||||
|
|
||||||
|
@ -65564,7 +65560,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
const id = b64_sha1('converse.bosh-session');
|
const id = b64_sha1('converse.bosh-session');
|
||||||
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
|
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
|
||||||
|
|
||||||
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
|
_converse.session.browserStorage = new Backbone.BrowserStorage.session(id);
|
||||||
|
|
||||||
_converse.session.fetch();
|
_converse.session.fetch();
|
||||||
|
|
||||||
|
@ -65682,7 +65678,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
_converse.log('An error occured while trying to enable message carbons.', Strophe.LogLevel.ERROR);
|
_converse.log('An error occured while trying to enable message carbons.', Strophe.LogLevel.ERROR);
|
||||||
} else {
|
} else {
|
||||||
this.session.save({
|
this.session.save({
|
||||||
carbons_enabled: true
|
'carbons_enabled': true
|
||||||
});
|
});
|
||||||
|
|
||||||
_converse.log('Message carbons have been enabled.');
|
_converse.log('Message carbons have been enabled.');
|
||||||
|
@ -66272,6 +66268,12 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
|
|
||||||
'send'(stanza) {
|
'send'(stanza) {
|
||||||
_converse.connection.send(stanza);
|
_converse.connection.send(stanza);
|
||||||
|
},
|
||||||
|
|
||||||
|
'sendIQ'(stanza) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // The public API
|
}; // The public API
|
||||||
|
@ -73287,6 +73289,94 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ "./src/converse-push.js":
|
||||||
|
/*!******************************!*\
|
||||||
|
!*** ./src/converse-push.js ***!
|
||||||
|
\******************************/
|
||||||
|
/*! no static exports found */
|
||||||
|
/***/ (function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
|
||||||
|
|
||||||
|
// Converse.js
|
||||||
|
// https://conversejs.org
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2018, the Converse.js developers
|
||||||
|
// Licensed under the Mozilla Public License (MPLv2)
|
||||||
|
|
||||||
|
/* This is a Converse.js plugin which add support for registering
|
||||||
|
* an "App Server" as defined in XEP-0357
|
||||||
|
*/
|
||||||
|
(function (root, factory) {
|
||||||
|
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! converse-core */ "./src/converse-core.js")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
|
||||||
|
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
|
||||||
|
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
|
||||||
|
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||||||
|
})(void 0, function (converse) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const _converse$env = converse.env,
|
||||||
|
Strophe = _converse$env.Strophe,
|
||||||
|
$iq = _converse$env.$iq;
|
||||||
|
Strophe.addNamespace('PUSH', 'urn:xmpp:push:0');
|
||||||
|
converse.plugins.add('converse-push', {
|
||||||
|
initialize() {
|
||||||
|
/* The initialize function gets called as soon as the plugin is
|
||||||
|
* loaded by converse.js's plugin machinery.
|
||||||
|
*/
|
||||||
|
const _converse = this._converse,
|
||||||
|
__ = _converse.__;
|
||||||
|
|
||||||
|
_converse.api.settings.update({
|
||||||
|
'push_service': undefined,
|
||||||
|
'push_service_node': undefined,
|
||||||
|
'push_service_secret': undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
function enablePush() {
|
||||||
|
if (_converse.session.get('push_enabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_converse.push_service && _converse.push_service_node) {
|
||||||
|
Promise.all([_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service), _converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service)]).then(() => _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid)).then(() => {
|
||||||
|
const stanza = $iq({
|
||||||
|
'type': 'set'
|
||||||
|
}).c('enable', {
|
||||||
|
'xmlns': Strophe.NS.PUSH,
|
||||||
|
'jid': _converse.push_service,
|
||||||
|
'node': _converse.push_service_node
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_converse.push_service_secret) {
|
||||||
|
stanza.c('x', {
|
||||||
|
'xmlns': Strophe.NS.XFORM,
|
||||||
|
'type': 'submit'
|
||||||
|
}).c('field', {
|
||||||
|
'var': 'FORM_TYPE'
|
||||||
|
}).c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up().c('field', {
|
||||||
|
'var': 'secret'
|
||||||
|
}).c('value').t(_converse.push_service_secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
_converse.api.sendIQ(stanza).then(() => _converse.session.set('push_enabled', true)).catch(e => {
|
||||||
|
_converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
|
||||||
|
|
||||||
|
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_converse.api.listen.on('statusInitialized', enablePush);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ "./src/converse-register.js":
|
/***/ "./src/converse-register.js":
|
||||||
/*!**********************************!*\
|
/*!**********************************!*\
|
||||||
!*** ./src/converse-register.js ***!
|
!*** ./src/converse-register.js ***!
|
||||||
|
@ -76844,7 +76934,8 @@ if (true) {
|
||||||
__webpack_require__(/*! converse-chatview */ "./src/converse-chatview.js"), // Renders standalone chat boxes for single user chat
|
__webpack_require__(/*! converse-chatview */ "./src/converse-chatview.js"), // Renders standalone chat boxes for single user chat
|
||||||
__webpack_require__(/*! converse-controlbox */ "./src/converse-controlbox.js"), // The control box
|
__webpack_require__(/*! converse-controlbox */ "./src/converse-controlbox.js"), // The control box
|
||||||
__webpack_require__(/*! converse-dragresize */ "./src/converse-dragresize.js"), // Allows chat boxes to be resized by dragging them
|
__webpack_require__(/*! converse-dragresize */ "./src/converse-dragresize.js"), // Allows chat boxes to be resized by dragging them
|
||||||
__webpack_require__(/*! converse-embedded */ "./src/converse-embedded.js"), __webpack_require__(/*! converse-fullscreen */ "./src/converse-fullscreen.js"), __webpack_require__(/*! converse-headline */ "./src/converse-headline.js"), // Support for headline messages
|
__webpack_require__(/*! converse-embedded */ "./src/converse-embedded.js"), __webpack_require__(/*! converse-fullscreen */ "./src/converse-fullscreen.js"), __webpack_require__(/*! converse-push */ "./src/converse-push.js"), // XEP-0357 Push Notifications
|
||||||
|
__webpack_require__(/*! converse-headline */ "./src/converse-headline.js"), // Support for headline messages
|
||||||
__webpack_require__(/*! converse-mam */ "./src/converse-mam.js"), // XEP-0313 Message Archive Management
|
__webpack_require__(/*! converse-mam */ "./src/converse-mam.js"), // XEP-0313 Message Archive Management
|
||||||
__webpack_require__(/*! converse-minimize */ "./src/converse-minimize.js"), // Allows chat boxes to be minimized
|
__webpack_require__(/*! converse-minimize */ "./src/converse-minimize.js"), // Allows chat boxes to be minimized
|
||||||
__webpack_require__(/*! converse-muc */ "./src/converse-muc.js"), // XEP-0045 Multi-user chat
|
__webpack_require__(/*! converse-muc */ "./src/converse-muc.js"), // XEP-0045 Multi-user chat
|
||||||
|
|
|
@ -7,10 +7,10 @@ Configuration
|
||||||
=============
|
=============
|
||||||
|
|
||||||
The included minified JavaScript and CSS files can be used for demoing or testing, but
|
The included minified JavaScript and CSS files can be used for demoing or testing, but
|
||||||
you'll want to configure *Converse.js* to suit your needs before you deploy it
|
you'll want to configure *Converse* to suit your needs before you deploy it
|
||||||
on your website.
|
on your website.
|
||||||
|
|
||||||
*Converse.js* is passed its configuration settings when you call its *initialize* method.
|
*Converse* is passed its configuration settings when you call its *initialize* method.
|
||||||
|
|
||||||
You'll most likely want to call the *initialize* method in your HTML page. For
|
You'll most likely want to call the *initialize* method in your HTML page. For
|
||||||
an example of how this is done, please see the bottom of the *./index.html* page.
|
an example of how this is done, please see the bottom of the *./index.html* page.
|
||||||
|
@ -18,7 +18,7 @@ an example of how this is done, please see the bottom of the *./index.html* page
|
||||||
Please refer to the `Configuration settings`_ section below for info on
|
Please refer to the `Configuration settings`_ section below for info on
|
||||||
all the available configuration settings.
|
all the available configuration settings.
|
||||||
|
|
||||||
After you have configured *Converse.js*, you'll have to regenerate the minified
|
After you have configured *Converse*, you'll have to regenerate the minified
|
||||||
JavaScript file so that it will include the new settings. Please refer to the
|
JavaScript file so that it will include the new settings. Please refer to the
|
||||||
:ref:`minification` section for more info on how to do this.
|
:ref:`minification` section for more info on how to do this.
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ requiring them to log in manually.
|
||||||
When a BOSH session is initially created, you'll receive three tokens.
|
When a BOSH session is initially created, you'll receive three tokens.
|
||||||
A JID (jabber ID), SID (session ID) and RID (Request ID).
|
A JID (jabber ID), SID (session ID) and RID (Request ID).
|
||||||
|
|
||||||
Converse.js needs these tokens in order to attach to that same session.
|
Converse needs these tokens in order to attach to that same session.
|
||||||
|
|
||||||
There are two complementary configuration settings to ``prebind``.
|
There are two complementary configuration settings to ``prebind``.
|
||||||
They are :ref:`keepalive` and `prebind_url`_.
|
They are :ref:`keepalive` and `prebind_url`_.
|
||||||
|
@ -200,7 +200,7 @@ allow_public_bookmarks
|
||||||
Some XMPP servers don't support private PEP/PubSub nodes, as required for
|
Some XMPP servers don't support private PEP/PubSub nodes, as required for
|
||||||
private bookmarks and outlined in `XEP-0223 <https://xmpp.org/extensions/xep-0223.html>`_.
|
private bookmarks and outlined in `XEP-0223 <https://xmpp.org/extensions/xep-0223.html>`_.
|
||||||
|
|
||||||
Even though Converse.js asks for the bookmarks to be kept private (via the
|
Even though Converse asks for the bookmarks to be kept private (via the
|
||||||
`<publish-options>` XML node), the server simply ignores the privacy settings
|
`<publish-options>` XML node), the server simply ignores the privacy settings
|
||||||
and publishes the node contents under the default privacy setting, which makes
|
and publishes the node contents under the default privacy setting, which makes
|
||||||
the information available to all roster contacts.
|
the information available to all roster contacts.
|
||||||
|
@ -382,7 +382,7 @@ A list of plugin names that are blacklisted and will therefore not be
|
||||||
initialized once ``converse.initialize`` is called, even if the same plugin is
|
initialized once ``converse.initialize`` is called, even if the same plugin is
|
||||||
whitelisted.
|
whitelisted.
|
||||||
|
|
||||||
From Converse.js 3.0 onwards most of the API is available only to plugins and
|
From Converse 3.0 onwards most of the API is available only to plugins and
|
||||||
all plugins need to be whitelisted first.
|
all plugins need to be whitelisted first.
|
||||||
|
|
||||||
The usecase for blacklisting is generally to disable removed core plugins
|
The usecase for blacklisting is generally to disable removed core plugins
|
||||||
|
@ -495,7 +495,7 @@ connection_options
|
||||||
* Default: ``{}``
|
* Default: ``{}``
|
||||||
* Type: Object
|
* Type: Object
|
||||||
|
|
||||||
Converse.js relies on `Strophe.js <http://strophe.im>`_ to establish and
|
Converse relies on `Strophe.js <http://strophe.im>`_ to establish and
|
||||||
maintain a connection to the XMPP server.
|
maintain a connection to the XMPP server.
|
||||||
|
|
||||||
This option allows you to pass a map of configuration options to be passed into
|
This option allows you to pass a map of configuration options to be passed into
|
||||||
|
@ -725,7 +725,7 @@ The translations for that locale must be available in JSON format at the
|
||||||
|
|
||||||
If an explicit locale is specified via the ``i18n`` setting and the
|
If an explicit locale is specified via the ``i18n`` setting and the
|
||||||
translations for that locale are not found at the `locales_url``, then
|
translations for that locale are not found at the `locales_url``, then
|
||||||
then Converse.js will fall back to trying to determine the browser's language
|
then Converse will fall back to trying to determine the browser's language
|
||||||
and fetching those translations, or if that fails the default English texts
|
and fetching those translations, or if that fails the default English texts
|
||||||
will be used.
|
will be used.
|
||||||
|
|
||||||
|
@ -747,7 +747,7 @@ keepalive
|
||||||
|
|
||||||
* Default: ``true``
|
* Default: ``true``
|
||||||
|
|
||||||
Determines whether Converse.js will maintain the chat session across page
|
Determines whether Converse will maintain the chat session across page
|
||||||
loads.
|
loads.
|
||||||
|
|
||||||
This setting should also be used in conjunction with ``authentication`` set to `prebind`_.
|
This setting should also be used in conjunction with ``authentication`` set to `prebind`_.
|
||||||
|
@ -785,7 +785,7 @@ locales
|
||||||
'ru', 'uk', 'zh'
|
'ru', 'uk', 'zh'
|
||||||
]
|
]
|
||||||
|
|
||||||
This setting restricts the locales that are supported by Converse.js and
|
This setting restricts the locales that are supported by Converse and
|
||||||
therefore what may be given as value for the :ref:`i18n` option.
|
therefore what may be given as value for the :ref:`i18n` option.
|
||||||
|
|
||||||
Any other locales will be ignored.
|
Any other locales will be ignored.
|
||||||
|
@ -800,7 +800,7 @@ locales_url
|
||||||
|
|
||||||
* Default: ``/locale/{{{locale}}}/LC_MESSAGES/converse.json``,
|
* Default: ``/locale/{{{locale}}}/LC_MESSAGES/converse.json``,
|
||||||
|
|
||||||
The URL from where Converse.js should fetch translation JSON.
|
The URL from where Converse should fetch translation JSON.
|
||||||
|
|
||||||
The three curly braces ``{{{ }}}`` are
|
The three curly braces ``{{{ }}}`` are
|
||||||
`Mustache <https://github.com/janl/mustache.js#readme>`_-style
|
`Mustache <https://github.com/janl/mustache.js#readme>`_-style
|
||||||
|
@ -812,7 +812,7 @@ The variable being interpolated via the curly braces is ``locale``, which is
|
||||||
the value passed in to the `i18n`_ setting, or the browser's locale or the
|
the value passed in to the `i18n`_ setting, or the browser's locale or the
|
||||||
default local or `en` (resolved in that order).
|
default local or `en` (resolved in that order).
|
||||||
|
|
||||||
From version 3.3.0, Converse.js no longer bundles all translations into its
|
From version 3.3.0, Converse no longer bundles all translations into its
|
||||||
final build file. Instead, only the relevant translations are fetched at
|
final build file. Instead, only the relevant translations are fetched at
|
||||||
runtime.
|
runtime.
|
||||||
|
|
||||||
|
@ -953,7 +953,7 @@ muc_show_join_leave
|
||||||
|
|
||||||
* Default; ``true``
|
* Default; ``true``
|
||||||
|
|
||||||
Determines whether Converse.js will show info messages inside a chatroom
|
Determines whether Converse will show info messages inside a chatroom
|
||||||
whenever a user joins or leaves it.
|
whenever a user joins or leaves it.
|
||||||
|
|
||||||
nickname
|
nickname
|
||||||
|
@ -1007,7 +1007,7 @@ play_sounds
|
||||||
Plays a notification sound when you receive a personal message or when your
|
Plays a notification sound when you receive a personal message or when your
|
||||||
nickname is mentioned in a chatroom.
|
nickname is mentioned in a chatroom.
|
||||||
|
|
||||||
Inside the ``./sounds`` directory of the Converse.js repo you'll see MP3 and Ogg
|
Inside the ``./sounds`` directory of the Converse repo you'll see MP3 and Ogg
|
||||||
formatted sound files. We need both, because neither format is supported by all browsers.
|
formatted sound files. We need both, because neither format is supported by all browsers.
|
||||||
|
|
||||||
You can set the URL where the sound files are hosted with the `sounds_path`_
|
You can set the URL where the sound files are hosted with the `sounds_path`_
|
||||||
|
@ -1047,12 +1047,12 @@ priority
|
||||||
* Type: Number
|
* Type: Number
|
||||||
|
|
||||||
Determines the priority used for presence stanzas sent out from this resource
|
Determines the priority used for presence stanzas sent out from this resource
|
||||||
(i.e. this instance of Converse.js).
|
(i.e. this instance of Converse).
|
||||||
|
|
||||||
The priority of a given XMPP chat client determines the importance of its presence
|
The priority of a given XMPP chat client determines the importance of its presence
|
||||||
stanzas in relation to stanzas received from other clients of the same user.
|
stanzas in relation to stanzas received from other clients of the same user.
|
||||||
|
|
||||||
In Converse.js, the indicated chat status of a roster contact will be taken from the
|
In Converse, the indicated chat status of a roster contact will be taken from the
|
||||||
presence stanza (and associated resource) with the highest priority.
|
presence stanza (and associated resource) with the highest priority.
|
||||||
|
|
||||||
If multiple resources have the same top priority, then the chat status will be
|
If multiple resources have the same top priority, then the chat status will be
|
||||||
|
@ -1068,6 +1068,39 @@ providers_link
|
||||||
The hyperlink on the registration form which points to a directory of public
|
The hyperlink on the registration form which points to a directory of public
|
||||||
XMPP servers.
|
XMPP servers.
|
||||||
|
|
||||||
|
push_service
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Default: ``undefined``
|
||||||
|
|
||||||
|
This option allows you to specify a URI for the push notifications service
|
||||||
|
(called an "App Server" by `XEP-0357 <https://xmpp.org/extensions/xep-0357.html>`_).
|
||||||
|
|
||||||
|
If provided, together with a `push_service_node`_, then Converse will instruct
|
||||||
|
the user's XMPP server to send push notificatiosn to that URI.
|
||||||
|
|
||||||
|
push_service_node
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* Default: ``undefined``
|
||||||
|
|
||||||
|
This is the PubSub node of the push notifications service (aka "App Server") specified with the
|
||||||
|
`push_service`_ setting.
|
||||||
|
|
||||||
|
Push notifications will be sent to this node. If this value is not set, then
|
||||||
|
push notifications won't be sent out.
|
||||||
|
|
||||||
|
push_service_secret
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Default: ``undefined``
|
||||||
|
|
||||||
|
Some push notification services (aka "App Servers") require a secret token to
|
||||||
|
be used when sending out notifications.
|
||||||
|
|
||||||
|
This setting enables you to provide such a secret to Converse which will
|
||||||
|
forward it to your XMPP server to be included in push notifications.
|
||||||
|
|
||||||
root
|
root
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -1108,7 +1141,7 @@ configured.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
It's currently not possible to use converse.js to assign contacts to groups.
|
It's currently not possible to use converse.js to assign contacts to groups.
|
||||||
Converse.js can only show users and groups that were previously configured
|
Converse can only show users and groups that were previously configured
|
||||||
elsewhere.
|
elsewhere.
|
||||||
|
|
||||||
show_chatstate_notifications
|
show_chatstate_notifications
|
||||||
|
@ -1262,10 +1295,10 @@ loaded), then an error will be raised.
|
||||||
|
|
||||||
Otherwise a message will simply be logged and the override instruction ignored.
|
Otherwise a message will simply be logged and the override instruction ignored.
|
||||||
|
|
||||||
The Converse.js plugins architecture can have an :ref:`dependencies`
|
The Converse plugins architecture can have an :ref:`dependencies`
|
||||||
plugin attribute. This enables you to specify an array of other plugins which
|
plugin attribute. This enables you to specify an array of other plugins which
|
||||||
this one depends on.
|
this one depends on.
|
||||||
Converse.js (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_)
|
Converse (more specifically, `pluggable.js <https://jcbrand.github.io/pluggable.js/>`_)
|
||||||
will first load these dependencies before executing the plugin's overrides and
|
will first load these dependencies before executing the plugin's overrides and
|
||||||
calling its ``initialize`` method.
|
calling its ``initialize`` method.
|
||||||
|
|
||||||
|
@ -1302,7 +1335,7 @@ This setting determines whether the default value of the "This is a trusted devi
|
||||||
When the current device is not trusted, then localStorage and sessionStorage
|
When the current device is not trusted, then localStorage and sessionStorage
|
||||||
will be cleared when the user logs out, thereby removing all cached data.
|
will be cleared when the user logs out, thereby removing all cached data.
|
||||||
|
|
||||||
Clearing the cache in this way makes Converse.js much slower when the user logs
|
Clearing the cache in this way makes Converse much slower when the user logs
|
||||||
in again, because all data needs to be fetch anew.
|
in again, because all data needs to be fetch anew.
|
||||||
|
|
||||||
See also `storage`_.
|
See also `storage`_.
|
||||||
|
@ -1323,7 +1356,7 @@ use_otr_by_default
|
||||||
|
|
||||||
* Default: ``false``
|
* Default: ``false``
|
||||||
|
|
||||||
If set to ``true``, Converse.js will automatically try to initiate an OTR (off-the-record)
|
If set to ``true``, Converse will automatically try to initiate an OTR (off-the-record)
|
||||||
encrypted chat session every time you open a chatbox.
|
encrypted chat session every time you open a chatbox.
|
||||||
|
|
||||||
visible_toolbar_buttons
|
visible_toolbar_buttons
|
||||||
|
@ -1382,7 +1415,7 @@ support.
|
||||||
configuration setting).
|
configuration setting).
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Converse.js does not yet support "keepalive" with websockets.
|
Converse does not yet support "keepalive" with websockets.
|
||||||
|
|
||||||
.. _`view_mode`:
|
.. _`view_mode`:
|
||||||
|
|
||||||
|
@ -1448,7 +1481,7 @@ whitelisted_plugins
|
||||||
A list of plugin names that are whitelisted and will therefore be
|
A list of plugin names that are whitelisted and will therefore be
|
||||||
initialized once ``converse.initialize`` is called.
|
initialized once ``converse.initialize`` is called.
|
||||||
|
|
||||||
From Converse.js 3.0 onwards most of the API is available only to plugins and
|
From Converse 3.0 onwards most of the API is available only to plugins and
|
||||||
all plugins need to be whitelisted first.
|
all plugins need to be whitelisted first.
|
||||||
|
|
||||||
This is done to prevent malicious scripts from using the API to trick users or
|
This is done to prevent malicious scripts from using the API to trick users or
|
||||||
|
|
119
spec/push.js
Normal file
119
spec/push.js
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
(function (root, factory) {
|
||||||
|
define(["jasmine", "mock", "test-utils"], factory);
|
||||||
|
} (this, function (jasmine, mock, test_utils) {
|
||||||
|
"use strict";
|
||||||
|
var $iq = converse.env.$iq;
|
||||||
|
var Strophe = converse.env.Strophe;
|
||||||
|
var _ = converse.env._;
|
||||||
|
|
||||||
|
describe("XEP-0357 Push Notifications", function () {
|
||||||
|
|
||||||
|
it("can be enabled by specifying a push_service and push_service_node",
|
||||||
|
mock.initConverseWithPromises(null,
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'push_service': 'push-5@client.example',
|
||||||
|
'push_service_node': 'yxs32uqsflafdk3iuqo'
|
||||||
|
}, function (done, _converse) {
|
||||||
|
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
let stanza;
|
||||||
|
|
||||||
|
expect(_converse.push_service).toBe('push-5@client.example');
|
||||||
|
expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
|
||||||
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.push_service,
|
||||||
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info')
|
||||||
|
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse,
|
||||||
|
_converse.bare_jid,
|
||||||
|
[{'category': 'account', 'type':'registered'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info'))
|
||||||
|
.then(() => {
|
||||||
|
return test_utils.waitUntil(() => {
|
||||||
|
const node = _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
|
||||||
|
}).pop();
|
||||||
|
if (node) {
|
||||||
|
stanza = node.nodeTree;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
expect(stanza.outerHTML).toEqual(
|
||||||
|
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
|
||||||
|
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo"/>'+
|
||||||
|
'</iq>'
|
||||||
|
)
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'result',
|
||||||
|
'id': stanza.getAttribute('id')
|
||||||
|
})));
|
||||||
|
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
|
||||||
|
}).then(() => {
|
||||||
|
done();
|
||||||
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it("can require a secret token to be included",
|
||||||
|
mock.initConverseWithPromises(null,
|
||||||
|
['rosterGroupsFetched'], {
|
||||||
|
'push_service': 'push-5@client.example',
|
||||||
|
'push_service_node': 'yxs32uqsflafdk3iuqo',
|
||||||
|
'push_service_secret': 'eruio234vzxc2kla-91'
|
||||||
|
}, function (done, _converse) {
|
||||||
|
|
||||||
|
const IQ_stanzas = _converse.connection.IQ_stanzas;
|
||||||
|
let stanza;
|
||||||
|
|
||||||
|
expect(_converse.push_service).toBe('push-5@client.example');
|
||||||
|
expect(_converse.push_service_node).toBe('yxs32uqsflafdk3iuqo');
|
||||||
|
expect(_converse.push_service_secret).toBe('eruio234vzxc2kla-91');
|
||||||
|
expect(_converse.session.get('push_enabled')).toBeFalsy();
|
||||||
|
|
||||||
|
test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse, _converse.push_service,
|
||||||
|
[{'category': 'pubsub', 'type':'push'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info')
|
||||||
|
.then(() => test_utils.waitUntilDiscoConfirmed(
|
||||||
|
_converse,
|
||||||
|
_converse.bare_jid,
|
||||||
|
[{'category': 'account', 'type':'registered'}],
|
||||||
|
['urn:xmpp:push:0'], [], 'info'))
|
||||||
|
.then(() => {
|
||||||
|
return test_utils.waitUntil(() => {
|
||||||
|
const node = _.filter(IQ_stanzas, function (iq) {
|
||||||
|
return iq.nodeTree.querySelector('iq[type="set"] enable[xmlns="urn:xmpp:push:0"]');
|
||||||
|
}).pop();
|
||||||
|
if (node) {
|
||||||
|
stanza = node.nodeTree;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
expect(stanza.outerHTML).toEqual(
|
||||||
|
`<iq type="set" xmlns="jabber:client" id="${stanza.getAttribute('id')}">`+
|
||||||
|
'<enable xmlns="urn:xmpp:push:0" jid="push-5@client.example" node="yxs32uqsflafdk3iuqo">'+
|
||||||
|
'<x xmlns="jabber:x:data" type="submit">'+
|
||||||
|
'<field var="FORM_TYPE"><value>http://jabber.org/protocol/pubsub#publish-options</value></field>'+
|
||||||
|
'<field var="secret"><value>eruio234vzxc2kla-91</value></field>'+
|
||||||
|
'</x>'+
|
||||||
|
'</enable>'+
|
||||||
|
'</iq>'
|
||||||
|
)
|
||||||
|
_converse.connection._dataRecv(test_utils.createRequest($iq({
|
||||||
|
'to': _converse.connection.jid,
|
||||||
|
'type': 'result',
|
||||||
|
'id': stanza.getAttribute('id')
|
||||||
|
})));
|
||||||
|
return test_utils.waitUntil(() => _converse.session.get('push_enabled'))
|
||||||
|
}).then(() => {
|
||||||
|
done();
|
||||||
|
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}));
|
|
@ -20,11 +20,7 @@
|
||||||
"backbone.browserStorage"
|
"backbone.browserStorage"
|
||||||
], factory);
|
], factory);
|
||||||
}(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
|
}(this, function (sizzle, Promise, _, f, polyfill, i18n, u, moment, Strophe, pluggable, Backbone) {
|
||||||
|
"use strict";
|
||||||
/* Cannot use this due to Safari bug.
|
|
||||||
* See https://github.com/jcbrand/converse.js/issues/196
|
|
||||||
*/
|
|
||||||
// "use strict";
|
|
||||||
|
|
||||||
// Strophe globals
|
// Strophe globals
|
||||||
const { $build, $iq, $msg, $pres } = Strophe;
|
const { $build, $iq, $msg, $pres } = Strophe;
|
||||||
|
@ -72,9 +68,9 @@
|
||||||
// Core plugins are whitelisted automatically
|
// Core plugins are whitelisted automatically
|
||||||
_converse.core_plugins = [
|
_converse.core_plugins = [
|
||||||
'converse-bookmarks',
|
'converse-bookmarks',
|
||||||
|
'converse-caps',
|
||||||
'converse-chatboxes',
|
'converse-chatboxes',
|
||||||
'converse-chatview',
|
'converse-chatview',
|
||||||
'converse-caps',
|
|
||||||
'converse-controlbox',
|
'converse-controlbox',
|
||||||
'converse-core',
|
'converse-core',
|
||||||
'converse-disco',
|
'converse-disco',
|
||||||
|
@ -89,9 +85,9 @@
|
||||||
'converse-muc',
|
'converse-muc',
|
||||||
'converse-muc-views',
|
'converse-muc-views',
|
||||||
'converse-notification',
|
'converse-notification',
|
||||||
'converse-otr',
|
|
||||||
'converse-ping',
|
'converse-ping',
|
||||||
'converse-profile',
|
'converse-profile',
|
||||||
|
'converse-push',
|
||||||
'converse-register',
|
'converse-register',
|
||||||
'converse-roomslist',
|
'converse-roomslist',
|
||||||
'converse-roster',
|
'converse-roster',
|
||||||
|
@ -131,6 +127,8 @@
|
||||||
_converse.OPENED = 'opened';
|
_converse.OPENED = 'opened';
|
||||||
_converse.PREBIND = "prebind";
|
_converse.PREBIND = "prebind";
|
||||||
|
|
||||||
|
_converse.IQ_TIMEOUT = 30000;
|
||||||
|
|
||||||
_converse.CONNECTION_STATUS = {
|
_converse.CONNECTION_STATUS = {
|
||||||
0: 'ERROR',
|
0: 'ERROR',
|
||||||
1: 'CONNECTING',
|
1: 'CONNECTING',
|
||||||
|
@ -298,7 +296,6 @@
|
||||||
|
|
||||||
|
|
||||||
_converse.initialize = function (settings, callback) {
|
_converse.initialize = function (settings, callback) {
|
||||||
"use strict";
|
|
||||||
settings = !_.isUndefined(settings) ? settings : {};
|
settings = !_.isUndefined(settings) ? settings : {};
|
||||||
const init_promise = u.getResolveablePromise();
|
const init_promise = u.getResolveablePromise();
|
||||||
|
|
||||||
|
@ -638,7 +635,7 @@
|
||||||
_converse.session = new Backbone.Model();
|
_converse.session = new Backbone.Model();
|
||||||
const id = b64_sha1('converse.bosh-session');
|
const id = b64_sha1('converse.bosh-session');
|
||||||
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
|
_converse.session.id = id; // Appears to be necessary for backbone.browserStorage
|
||||||
_converse.session.browserStorage = new Backbone.BrowserStorage[_converse.storage](id);
|
_converse.session.browserStorage = new Backbone.BrowserStorage.session(id);
|
||||||
_converse.session.fetch();
|
_converse.session.fetch();
|
||||||
_converse.emit('sessionInitialized');
|
_converse.emit('sessionInitialized');
|
||||||
};
|
};
|
||||||
|
@ -739,7 +736,7 @@
|
||||||
'An error occured while trying to enable message carbons.',
|
'An error occured while trying to enable message carbons.',
|
||||||
Strophe.LogLevel.ERROR);
|
Strophe.LogLevel.ERROR);
|
||||||
} else {
|
} else {
|
||||||
this.session.save({carbons_enabled: true});
|
this.session.save({'carbons_enabled': true});
|
||||||
_converse.log('Message carbons have been enabled.');
|
_converse.log('Message carbons have been enabled.');
|
||||||
}
|
}
|
||||||
}, null, "iq", null, "enablecarbons");
|
}, null, "iq", null, "enablecarbons");
|
||||||
|
@ -1289,6 +1286,11 @@
|
||||||
'send' (stanza) {
|
'send' (stanza) {
|
||||||
_converse.connection.send(stanza);
|
_converse.connection.send(stanza);
|
||||||
},
|
},
|
||||||
|
'sendIQ' (stanza) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
_converse.connection.sendIQ(stanza, resolve, reject, _converse.IQ_TIMEOUT);
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The public API
|
// The public API
|
||||||
|
|
70
src/converse-push.js
Normal file
70
src/converse-push.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
// Converse.js
|
||||||
|
// https://conversejs.org
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2018, the Converse.js developers
|
||||||
|
// Licensed under the Mozilla Public License (MPLv2)
|
||||||
|
|
||||||
|
/* This is a Converse.js plugin which add support for registering
|
||||||
|
* an "App Server" as defined in XEP-0357
|
||||||
|
*/
|
||||||
|
(function (root, factory) {
|
||||||
|
define(["converse-core"], factory);
|
||||||
|
}(this, function (converse) {
|
||||||
|
"use strict";
|
||||||
|
const { Strophe, $iq } = converse.env;
|
||||||
|
|
||||||
|
|
||||||
|
Strophe.addNamespace('PUSH', 'urn:xmpp:push:0');
|
||||||
|
|
||||||
|
|
||||||
|
converse.plugins.add('converse-push', {
|
||||||
|
|
||||||
|
initialize () {
|
||||||
|
/* The initialize function gets called as soon as the plugin is
|
||||||
|
* loaded by converse.js's plugin machinery.
|
||||||
|
*/
|
||||||
|
const { _converse } = this,
|
||||||
|
{ __ } = _converse;
|
||||||
|
|
||||||
|
_converse.api.settings.update({
|
||||||
|
'push_service': undefined,
|
||||||
|
'push_service_node': undefined,
|
||||||
|
'push_service_secret': undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
function enablePush() {
|
||||||
|
if (_converse.session.get('push_enabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_converse.push_service && _converse.push_service_node) {
|
||||||
|
Promise.all([
|
||||||
|
_converse.api.disco.getIdentity('pubsub', 'push', _converse.push_service),
|
||||||
|
_converse.api.disco.supports(Strophe.NS.PUSH, _converse.push_service)
|
||||||
|
]).then(() => _converse.api.disco.supports(Strophe.NS.PUSH, _converse.bare_jid))
|
||||||
|
.then(() => {
|
||||||
|
const stanza = $iq({'type': 'set'})
|
||||||
|
.c('enable', {
|
||||||
|
'xmlns': Strophe.NS.PUSH,
|
||||||
|
'jid': _converse.push_service,
|
||||||
|
'node': _converse.push_service_node
|
||||||
|
});
|
||||||
|
if (_converse.push_service_secret) {
|
||||||
|
stanza.c('x', {'xmlns': Strophe.NS.XFORM, 'type': 'submit'})
|
||||||
|
.c('field', {'var': 'FORM_TYPE'})
|
||||||
|
.c('value').t(`${Strophe.NS.PUBSUB}#publish-options`).up().up()
|
||||||
|
.c('field', {'var': 'secret'})
|
||||||
|
.c('value').t(_converse.push_service_secret);
|
||||||
|
}
|
||||||
|
_converse.api.sendIQ(stanza)
|
||||||
|
.then(() => _converse.session.set('push_enabled', true))
|
||||||
|
.catch((e) => {
|
||||||
|
_converse.log(`Could not enable push service for ${_converse.push_service}`, Strophe.LogLevel.ERROR);
|
||||||
|
_converse.log(e, Strophe.LogLevel.ERROR);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_converse.api.listen.on('statusInitialized', enablePush);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}));
|
|
@ -14,6 +14,7 @@ if (typeof define !== 'undefined') {
|
||||||
"converse-dragresize", // Allows chat boxes to be resized by dragging them
|
"converse-dragresize", // Allows chat boxes to be resized by dragging them
|
||||||
"converse-embedded",
|
"converse-embedded",
|
||||||
"converse-fullscreen",
|
"converse-fullscreen",
|
||||||
|
"converse-push", // XEP-0357 Push Notifications
|
||||||
"converse-headline", // Support for headline messages
|
"converse-headline", // Support for headline messages
|
||||||
"converse-mam", // XEP-0313 Message Archive Management
|
"converse-mam", // XEP-0313 Message Archive Management
|
||||||
"converse-minimize", // Allows chat boxes to be minimized
|
"converse-minimize", // Allows chat boxes to be minimized
|
||||||
|
|
|
@ -191,6 +191,7 @@ var specs = [
|
||||||
"spec/presence",
|
"spec/presence",
|
||||||
"spec/eventemitter",
|
"spec/eventemitter",
|
||||||
"spec/ping",
|
"spec/ping",
|
||||||
|
"spec/push",
|
||||||
"spec/xmppstatus",
|
"spec/xmppstatus",
|
||||||
"spec/mam",
|
"spec/mam",
|
||||||
// "spec/otr",
|
// "spec/otr",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user