Browse Source

Bugfix for headline messages.

Couldn't handle messages with no "from" attribute.
Some refactoring to add code that checks if a messages is a headline to the
utils module.
Updated tests. Add sinon so that we can test returned value of spy.
JC Brand 9 years ago
parent
commit
f353fe8611
9 changed files with 96 additions and 36 deletions
  1. 2 1
      bower.json
  2. 1 0
      jshintrc
  3. 33 6
      spec/chatbox.js
  4. 7 5
      spec/headline.js
  5. 24 7
      src/converse-core.js
  6. 3 6
      src/converse-headline.js
  7. 6 9
      src/converse-notification.js
  8. 15 0
      src/utils.js
  9. 5 2
      tests/main.js

+ 2 - 1
bower.json

@@ -30,7 +30,8 @@
     "skeleton-sass": "~2.0.3",
     "skeleton-sass": "~2.0.3",
     "strophejs": "1.2.4",
     "strophejs": "1.2.4",
     "strophejs-plugins": "https://github.com/strophe/strophejs-plugins.git#amd",
     "strophejs-plugins": "https://github.com/strophe/strophejs-plugins.git#amd",
-    "bourbon": "~4.2.3"
+    "bourbon": "~4.2.3",
+    "sinon": "^1.17.3"
   },
   },
   "resolutions": {
   "resolutions": {
     "backbone": "1.1.2"
     "backbone": "1.1.2"

+ 1 - 0
jshintrc

@@ -20,6 +20,7 @@
         "global",
         "global",
         "it",
         "it",
         "jasmine",
         "jasmine",
+        "sinon",
         "module",
         "module",
         "require",
         "require",
         "runs",
         "runs",

+ 33 - 6
spec/chatbox.js

@@ -3,13 +3,11 @@
     define([
     define([
         "jquery",
         "jquery",
         "underscore",
         "underscore",
+        "utils",
         "mock",
         "mock",
         "test_utils"
         "test_utils"
-        ], function ($, _, mock, test_utils) {
-            return factory($, _, mock, test_utils);
-        }
-    );
-} (this, function ($, _, mock, test_utils) {
+        ], factory);
+} (this, function ($, _, utils, mock, test_utils) {
     var $msg = converse_api.env.$msg;
     var $msg = converse_api.env.$msg;
     var Strophe = converse_api.env.Strophe;
     var Strophe = converse_api.env.Strophe;
     var moment = converse_api.env.moment;
     var moment = converse_api.env.moment;
@@ -461,6 +459,7 @@
                 it("is ignored if it's intended for a different resource", function () {
                 it("is ignored if it's intended for a different resource", function () {
                     // Send a message from a different resource
                     // Send a message from a different resource
                     spyOn(converse, 'log');
                     spyOn(converse, 'log');
+                    spyOn(converse.chatboxes, 'getChatBox');
                     var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
                     var sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
                     var msg = $msg({
                     var msg = $msg({
                             from: sender_jid,
                             from: sender_jid,
@@ -471,7 +470,35 @@
                         .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
                         .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree();
                     converse.chatboxes.onMessage(msg);
                     converse.chatboxes.onMessage(msg);
                     expect(converse.log).toHaveBeenCalledWith(
                     expect(converse.log).toHaveBeenCalledWith(
-                            "Ignore incoming message intended for a different resource: dummy@localhost/some-other-resource", "info");
+                            "onMessage: Ignoring incoming message intended for a different resource: dummy@localhost/some-other-resource", "info");
+                    expect(converse.chatboxes.getChatBox).not.toHaveBeenCalled();
+                });
+
+                it("is ignored if it's a malformed headline message", function () {
+                    /* Ideally we wouldn't have to filter out headline
+                     * messages, but Prosody gives them the wrong 'type' :(
+                     */
+                    sinon.spy(converse, 'log');
+                    sinon.spy(converse.chatboxes, 'getChatBox');
+                    sinon.spy(utils, 'isHeadlineMessage');
+                    var msg = $msg({
+                            from: 'localhost',
+                            to: converse.bare_jid,
+                            type: 'chat',
+                            id: (new Date()).getTime()
+                        }).c('body').t("This headline message will not be shown").tree();
+                    converse.chatboxes.onMessage(msg);
+                    expect(converse.log.calledWith(
+                        "onMessage: Ignoring incoming headline message sent with type 'chat' from JID: localhost",
+                        "info"
+                    )).toBeTruthy();
+                    expect(utils.isHeadlineMessage.called).toBeTruthy();
+                    expect(utils.isHeadlineMessage.returned(true)).toBeTruthy();
+                    expect(converse.chatboxes.getChatBox.called).toBeFalsy();
+                    // Remove sinon spies
+                    converse.log.restore();
+                    converse.chatboxes.getChatBox.restore();
+                    utils.isHeadlineMessage.restore();
                 });
                 });
 
 
                 it("can be a carbon message, as defined in XEP-0280", function () {
                 it("can be a carbon message, as defined in XEP-0280", function () {

+ 7 - 5
spec/headline.js

@@ -2,13 +2,11 @@
 (function (root, factory) {
 (function (root, factory) {
     define([
     define([
         "jquery",
         "jquery",
+        "utils",
         "mock",
         "mock",
         "test_utils"
         "test_utils"
-        ], function ($, mock, test_utils) {
-            return factory($, mock, test_utils);
-        }
-    );
-} (this, function ($, mock, test_utils) {
+        ], factory);
+} (this, function ($, utils, mock, test_utils) {
     "use strict";
     "use strict";
     var $msg = converse_api.env.$msg,
     var $msg = converse_api.env.$msg,
         _ = converse_api.env._;
         _ = converse_api.env._;
@@ -30,6 +28,7 @@
              *  </x>
              *  </x>
              *  </message>
              *  </message>
              */
              */
+            sinon.spy(utils, 'isHeadlineMessage');
             runs(function () {
             runs(function () {
                 var stanza = $msg({
                 var stanza = $msg({
                         'type': 'headline',
                         'type': 'headline',
@@ -50,6 +49,9 @@
                         converse.chatboxviews.keys(),
                         converse.chatboxviews.keys(),
                         'notify.example.com')
                         'notify.example.com')
                     ).toBeTruthy();
                     ).toBeTruthy();
+                expect(utils.isHeadlineMessage.called).toBeTruthy();
+                expect(utils.isHeadlineMessage.returned(true)).toBeTruthy();
+                utils.isHeadlineMessage.restore(); // unwraps
             });
             });
         });
         });
     });
     });

+ 24 - 7
src/converse-core.js

@@ -1308,22 +1308,39 @@
             },
             },
 
 
             onMessage: function (message) {
             onMessage: function (message) {
-                /* Handler method for all incoming single-user chat "message" stanzas.
+                /* Handler method for all incoming single-user chat "message"
+                 * stanzas.
                  */
                  */
                 var $message = $(message),
                 var $message = $(message),
-                    contact_jid, $forwarded, $delay, from_bare_jid, from_resource, is_me, msgid,
+                    contact_jid, $forwarded, $delay, from_bare_jid,
+                    from_resource, is_me, msgid,
                     chatbox, resource,
                     chatbox, resource,
                     from_jid = $message.attr('from'),
                     from_jid = $message.attr('from'),
                     to_jid = $message.attr('to'),
                     to_jid = $message.attr('to'),
                     to_resource = Strophe.getResourceFromJid(to_jid);
                     to_resource = Strophe.getResourceFromJid(to_jid);
 
 
                 if (to_resource && to_resource !== converse.resource) {
                 if (to_resource && to_resource !== converse.resource) {
-                    converse.log('Ignore incoming message intended for a different resource: '+to_jid, 'info');
+                    converse.log(
+                        'onMessage: Ignoring incoming message intended for a different resource: '+to_jid,
+                        'info'
+                    );
                     return true;
                     return true;
-                }
-                if (from_jid === converse.connection.jid) {
-                    // FIXME: Forwarded messages should be sent to specific resources, not broadcasted
-                    converse.log("Ignore incoming message sent from this client's JID: "+from_jid, 'info');
+                } else if (from_jid === converse.connection.jid) {
+                    // FIXME: Forwarded messages should be sent to specific
+                    // resources, not broadcasted
+                    converse.log(
+                        "onMessage: Ignoring incoming message sent from this client's JID: "+from_jid,
+                        'info'
+                    );
+                    return true;
+                } else if (utils.isHeadlineMessage(message)) {
+                    // XXX: Ideally we wouldn't have to check for headline
+                    // messages, but Prosody sends headline messages with the
+                    // wrong type ('chat'), so we need to filter them out here.
+                    converse.log(
+                        "onMessage: Ignoring incoming headline message sent with type 'chat' from JID: "+from_jid,
+                        'info'
+                    );
                     return true;
                     return true;
                 }
                 }
                 $forwarded = $message.find('forwarded');
                 $forwarded = $message.find('forwarded');

+ 3 - 6
src/converse-headline.js

@@ -22,12 +22,9 @@
     var onHeadlineMessage = function (message) {
     var onHeadlineMessage = function (message) {
         /* Handler method for all incoming messages of type "headline".
         /* Handler method for all incoming messages of type "headline".
          */
          */
-        var $message = $(message), from_jid = $message.attr('from');
-        if ($message.attr('type') === 'headline' || from_jid.indexOf('@') === -1) {
-            // Some servers (I'm looking at you Prosody) don't set the message
-            // type to "headline" when sending server messages. For now we
-            // check if an @ signal is included, and if not, we assume it's
-            // a headline message.
+        var $message = $(message),
+            from_jid = $message.attr('from');
+        if (utils.isHeadlineMessage(message)) {
             converse.chatboxes.create({
             converse.chatboxes.create({
                 'id': from_jid,
                 'id': from_jid,
                 'jid': from_jid,
                 'jid': from_jid,

+ 6 - 9
src/converse-notification.js

@@ -68,19 +68,16 @@
                 return true;
                 return true;
             };
             };
 
 
-            converse.shouldNotifyOfMessage = function ($message) {
+            converse.shouldNotifyOfMessage = function (message) {
                 /* Is this a message worthy of notification?
                 /* Is this a message worthy of notification?
                  */
                  */
-                var $forwarded = $message.find('forwarded');
+                var $message = $(message),
+                    $forwarded = $message.find('forwarded');
                 if ($forwarded.length) {
                 if ($forwarded.length) {
                     return false;
                     return false;
-                }
-                if ($message.attr('type') === 'groupchat') {
+                } else if ($message.attr('type') === 'groupchat') {
                     return converse.shouldNotifyOfGroupMessage($message);
                     return converse.shouldNotifyOfGroupMessage($message);
-                }
-                if ($message.attr('type') === 'headline' || $message.attr('from').indexOf('@') === -1) {
-                    // XXX: 2nd check is workaround for Prosody which doesn't give type "headline"
-
+                } else if (utils.isHeadlineMessage(message)) {
                     // We want to show notifications for headline messages.
                     // We want to show notifications for headline messages.
                     return true;
                     return true;
                 }
                 }
@@ -198,7 +195,7 @@
                  * to play sounds and show HTML5 notifications.
                  * to play sounds and show HTML5 notifications.
                  */
                  */
                 var $message = $(message);
                 var $message = $(message);
-                if (!converse.shouldNotifyOfMessage($message)) {
+                if (!converse.shouldNotifyOfMessage(message)) {
                     return false;
                     return false;
                 }
                 }
                 converse.playSoundNotification($message);
                 converse.playSoundNotification($message);

+ 15 - 0
src/utils.js

@@ -125,6 +125,21 @@
             return str;
             return str;
         },
         },
 
 
+        isHeadlineMessage: function (message) {
+            var $message = $(message),
+                from_jid = $message.attr('from');
+            if ($message.attr('type') === 'headline' ||
+                    // Some servers (I'm looking at you Prosody) don't set the message
+                    // type to "headline" when sending server messages. For now we
+                    // check if an @ signal is included, and if not, we assume it's
+                    // a headline message.
+                    (typeof from_jid !== 'undefined' && from_jid.indexOf('@') === -1)
+                ) {
+                return true;
+            }
+            return false;
+        },
+
         refreshWebkit: function () {
         refreshWebkit: function () {
             /* This works around a webkit bug. Refreshes the browser's viewport,
             /* This works around a webkit bug. Refreshes the browser's viewport,
              * otherwise chatboxes are not moved along when one is closed.
              * otherwise chatboxes are not moved along when one is closed.

+ 5 - 2
tests/main.js

@@ -1,6 +1,7 @@
 // Extra test dependencies
 // Extra test dependencies
 config.paths.mock = "tests/mock";
 config.paths.mock = "tests/mock";
 config.paths.test_utils = "tests/utils";
 config.paths.test_utils = "tests/utils";
+config.paths.sinon = "components/sinon/lib/sinon";
 config.paths.jasmine = "components/jasmine/lib/jasmine-core/jasmine";
 config.paths.jasmine = "components/jasmine/lib/jasmine-core/jasmine";
 config.paths["jasmine-html"] = "components/jasmine/lib/jasmine-core/jasmine-html";
 config.paths["jasmine-html"] = "components/jasmine/lib/jasmine-core/jasmine-html";
 config.paths["console-runner"] = "node_modules/phantom-jasmine/lib/console-runner";
 config.paths["console-runner"] = "node_modules/phantom-jasmine/lib/console-runner";
@@ -34,9 +35,11 @@ require([
     "jquery",
     "jquery",
     "converse",
     "converse",
     "mock",
     "mock",
-    "jasmine-html"
-    ], function($, converse, mock, jasmine) {
+    "jasmine-html",
+    "sinon"
+    ], function($, converse, mock, jasmine, sinon) {
         // Set up converse.js
         // Set up converse.js
+        window.sinon = sinon;
         window.converse_api = converse;
         window.converse_api = converse;
         window.localStorage.clear();
         window.localStorage.clear();
         window.sessionStorage.clear();
         window.sessionStorage.clear();