2
0
Эх сурвалжийг харах

Add the ability to read and set MAM preferences.

JC Brand 10 жил өмнө
parent
commit
eeeaddbe04
4 өөрчлөгдсөн 174 нэмэгдсэн , 0 устгасан
  1. 54 0
      converse.js
  2. 13 0
      docs/source/configuration.rst
  3. 106 0
      spec/mam.js
  4. 1 0
      tests/main.js

+ 54 - 0
converse.js

@@ -313,6 +313,7 @@
             hide_offline_users: false,
             jid: undefined,
             keepalive: false,
+            message_archiving: 'never', // Supported values are 'always', 'never', 'roster' (See https://xmpp.org/extensions/xep-0313.html#prefs )
             message_carbons: false, // Support for XEP-280
             no_trimming: false, // Set to true for phantomjs tests (where browser apparently has no width)
             ping_interval: 180, //in seconds
@@ -5041,6 +5042,7 @@
                 this.addClientIdentities().addClientFeatures();
                 this.browserStorage = new Backbone.BrowserStorage[converse.storage](
                     b64_sha1('converse.features'+converse.bare_jid));
+                this.on('add', this.onFeatureAdded, this);
                 if (this.browserStorage.records.length === 0) {
                     // browserStorage is empty, so we've likely never queried this
                     // domain for features yet
@@ -5051,6 +5053,58 @@
                 }
             },
 
+            onFeatureAdded: function (feature) {
+                if (feature.get('var') == Strophe.NS.MAM) {
+                    // Ask the server for archiving preferences
+                    converse.connection.sendIQ(
+                        $iq({'type': 'get'}).c('prefs', {'xmlns': Strophe.NS.MAM}),
+                        _.bind(this.onMAMPreferences, this, feature),
+                        _.bind(this.onMAMError, this, feature)
+                    );
+                }
+            },
+
+            onMAMPreferences: function (feature, iq) {
+                /* Handle returned IQ stanza containing Message Archive
+                 * Management (XEP-0313) preferences.
+                 *
+                 * XXX: For now we only handle the global default preference.
+                 * The XEP also provides for per-JID preferences, which is
+                 * currently not supported in converse.js.
+                 *
+                 * Per JID preferences will be set in chat boxes, so it'll
+                 * probbaly be handled elsewhere in any case.
+                 */
+                var $prefs = $(iq).find('prefs[xmlns="'+Strophe.NS.MAM+'"]');
+                var default_pref = $prefs.attr('default');
+                var stanza;
+                if (default_pref !== converse.message_archiving) {
+                    stanza = $iq({'type': 'set'}).c('prefs', {'xmlns':Strophe.NS.MAM, 'default':converse.message_archiving});
+                    $prefs.children().each(function (idx, child) {
+                        stanza.cnode(child).up();
+                    });
+                    converse.connection.sendIQ(stanza, _.bind(function (feature, iq) {
+                            // XXX: Strictly speaking, the server should respond with the updated prefs
+                            // (see example 18: https://xmpp.org/extensions/xep-0313.html#config)
+                            // but Prosody doesn't do this, so we don't rely on it.
+                            feature.save({'preferences': {'default':converse.message_archiving}});
+                        }, this, feature),
+                        _.bind(this.onMAMError, this, feature)
+                    );
+                } else {
+                    feature.save({'preferences': {'default':converse.message_archiving}});
+                }
+            },
+
+            onMAMError: function (iq) {
+                if ($(iq).find('feature-not-implemented').length) {
+                    converse.log("Message Archive Management (XEP-0313) not supported by this browser");
+                } else {
+                    converse.log("An error occured while trying to set archiving preferences.");
+                    converse.log(iq);
+                }
+            },
+
             addClientIdentities: function () {
                 /* See http://xmpp.org/registrar/disco-categories.html
                  */

+ 13 - 0
docs/source/configuration.rst

@@ -327,6 +327,19 @@ See also:
     `XEP-0198 <http://xmpp.org/extensions/xep-0198.html>`_, specifically
     with regards to "stream resumption".
 
+
+message_archives
+----------------
+
+* Default:  ``never``
+
+Provides support for `XEP-0313: Message Archive Management <https://xmpp.org/extensions/xep-0313.html>`_
+
+This sets the default archiving preference. Valid values are ``never``, ``always`` and ``roster``.
+
+``roster`` means that only messages to and from JIDs in your roster will be
+archived. The other two values are self-explanatory.
+
 message_carbons
 ---------------
 

+ 106 - 0
spec/mam.js

@@ -0,0 +1,106 @@
+(function (root, factory) {
+    define([
+        "jquery",
+        "mock",
+        "test_utils"
+        ], function ($, mock, test_utils) {
+            return factory($, mock, test_utils);
+        }
+    );
+} (this, function ($, mock, test_utils) {
+    "use strict";
+    var Strophe = converse_api.env.Strophe;
+    var $iq = converse_api.env.$iq;
+    var $pres = converse_api.env.$pres;
+    // See:
+    // https://xmpp.org/rfcs/rfc3921.html
+
+    describe("Message Archive Management", $.proxy(function (mock, test_utils) {
+        // Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
+
+        describe("The default preference", $.proxy(function (mock, test_utils) {
+            beforeEach(function () {
+                test_utils.closeAllChatBoxes();
+                test_utils.removeControlBox();
+                converse.roster.browserStorage._clear();
+                test_utils.initConverse();
+                test_utils.openControlBox();
+                test_utils.openContactsPanel();
+            });
+
+            it("is set once server support for MAM has been confirmed", function () {
+                var sent_stanza, IQ_id;
+                var sendIQ = converse.connection.sendIQ;
+                spyOn(converse.connection, 'sendIQ').andCallFake(function (iq, callback, errback) {
+                    sent_stanza = iq;
+                    IQ_id = sendIQ.bind(this)(iq, callback, errback);
+                });
+                spyOn(converse.features, 'onMAMPreferences').andCallThrough();
+
+                var feature = new converse.Feature({
+                    'var': Strophe.NS.MAM
+                });
+                spyOn(feature, 'save').andCallFake(feature.set); // Save will complain about a url not being set
+                converse.features.onFeatureAdded(feature);
+
+                expect(converse.connection.sendIQ).toHaveBeenCalled();
+                expect(sent_stanza.toLocaleString()).toBe(
+                    "<iq type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
+                        "<prefs xmlns='urn:xmpp:mam:0'/>"+
+                    "</iq>"
+                );
+
+                converse.message_archiving = 'never';
+                /* Example 15. Server responds with current preferences
+                 *
+                 * <iq type='result' id='juliet2'>
+                 *   <prefs xmlns='urn:xmpp:mam:0' default='roster'>
+                 *     <always/>
+                 *     <never/>
+                 *   </prefs>
+                 * </iq>
+                 */
+                var stanza = $iq({'type': 'result', 'id': IQ_id})
+                    .c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'roster'})
+                    .c('always').c('jid').t('romeo@montague.lit').up().up()
+                    .c('never').c('jid').t('montague@montague.lit');
+                converse.connection._dataRecv(test_utils.createRequest(stanza));
+
+                expect(converse.features.onMAMPreferences).toHaveBeenCalled();
+
+                expect(converse.connection.sendIQ.callCount).toBe(2);
+                expect(sent_stanza.toString()).toBe(
+                    "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
+                        "<prefs xmlns='urn:xmpp:mam:0' default='never'>"+
+                            "<always><jid>romeo@montague.lit</jid></always>"+
+                            "<never><jid>montague@montague.lit</jid></never>"+
+                        "</prefs>"+
+                    "</iq>"
+                );
+
+                expect(feature.get('preference')).toBe(undefined);
+                /* <iq type='result' id='juliet3'>
+                 *   <prefs xmlns='urn:xmpp:mam:0' default='always'>
+                 *       <always>
+                 *          <jid>romeo@montague.lit</jid>
+                 *       </always>
+                 *       <never>
+                 *          <jid>montague@montague.lit</jid>
+                 *       </never>
+                 *   </prefs>
+                 * </iq>
+                 */
+                stanza = $iq({'type': 'result', 'id': IQ_id})
+                    .c('prefs', {'xmlns': Strophe.NS.MAM, 'default':'always'})
+                    .c('always').up()
+                    .c('never').up();
+                converse.connection._dataRecv(test_utils.createRequest(stanza));
+                expect(feature.save).toHaveBeenCalled();
+                expect(feature.get('preferences').default).toBe('never');
+
+                // Restore
+                converse.message_archiving = 'never';
+            });
+        }, converse, mock, test_utils));
+    }, converse, mock, test_utils));
+}));

+ 1 - 0
tests/main.js

@@ -61,6 +61,7 @@ require([
                 "console-runner",
                 "spec/converse",
                 "spec/protocol",
+                "spec/mam",
                 "spec/otr",
                 "spec/eventemitter",
                 "spec/controlbox",