[tor-commits] [tor-messenger-build/master] Rebase the preparation patch
arlo at torproject.org
arlo at torproject.org
Thu Nov 27 03:32:10 UTC 2014
commit 6e77842b91dae35d0dc05adde4cf96ff0533fc42
Author: Arlo Breault <arlolra at gmail.com>
Date: Wed Nov 26 19:31:11 2014 -0800
Rebase the preparation patch
* And add the tests patch for good measure.
---
projects/instantbird/config | 5 +-
.../prepare-messages-for-displaying.patch | 40 ++-
projects/instantbird/test-transformation-api.patch | 367 ++++++++++++++++++++
3 files changed, 392 insertions(+), 20 deletions(-)
diff --git a/projects/instantbird/config b/projects/instantbird/config
index f49d4f8..ce37906 100644
--- a/projects/instantbird/config
+++ b/projects/instantbird/config
@@ -56,14 +56,15 @@ input_files:
project: mozilla
pkg_type: src
- filename: preferences.patch
- - filename: irc.patch
+ - filename: prepare-messages-for-displaying.patch
+ - filename: test-transformation-api.patch
- filename: slashme.patch
+ - filename: irc.patch
- filename: xmpp.patch
- filename: facebook.patch
- filename: accountcreation.patch
- filename: links.patch
- filename: picture.patch
- - filename: prepare-messages-for-displaying.patch
- filename: spi-cacert.der
- filename: ccc-jabber-cacert.der
- filename: fix-mingw-build.nsprpatch
diff --git a/projects/instantbird/prepare-messages-for-displaying.patch b/projects/instantbird/prepare-messages-for-displaying.patch
index 1796a0c..4828728 100644
--- a/projects/instantbird/prepare-messages-for-displaying.patch
+++ b/projects/instantbird/prepare-messages-for-displaying.patch
@@ -1,9 +1,9 @@
# HG changeset patch
# User Arlo Breault <arlolra at gmail.com>
-# Date 1411421387 25200
-# Mon Sep 22 14:29:47 2014 -0700
-# Node ID fbe43529c92d26a1c7674fc964ae5e1aadc9ac2f
-# Parent 2b6f0a6859958c9b57b3975001ee7aac257d9ae8
+# Date 1417058407 28800
+# Wed Nov 26 19:20:07 2014 -0800
+# Node ID 0108590a22b0943081fe0f26375834da2f84b0b6
+# Parent e4c698528d69e8d4e2116bbf2e28f91fd5b5f972
Prepare messages for displaying
* Adds a converse method to prepareForSending.
@@ -56,7 +56,7 @@ diff --git a/chat/components/public/prplIConversation.idl b/chat/components/publ
* This is the XPCOM purple conversation component, a proxy for PurpleConversation.
*/
-@@ -47,16 +48,19 @@ interface prplIConversation: nsISupports
+@@ -47,16 +48,21 @@ interface prplIConversation: nsISupports
void sendMsg(in AUTF8String aMsg);
/* Preprocess messages before they are sent (eg. split long messages).
@@ -65,7 +65,9 @@ diff --git a/chat/components/public/prplIConversation.idl b/chat/components/publ
[optional] out unsigned long aMsgCount,
[retval, array, size_is(aMsgCount)] out wstring aMsgs);
-+ /* Postprocess messages before they are displayed (eg. escaping). */
++ /* Postprocess messages before they are displayed (eg. escaping). The
++ implementation can set aMsg.displayMessage, otherwise the originalMessage
++ is used. */
+ void prepareForDisplaying(in imIMessage aMsg);
+
/* Send information about the current typing state to the server.
@@ -79,7 +81,7 @@ diff --git a/chat/components/public/prplIConversation.idl b/chat/components/publ
diff --git a/chat/components/src/imConversations.js b/chat/components/src/imConversations.js
--- a/chat/components/src/imConversations.js
+++ b/chat/components/src/imConversations.js
-@@ -399,16 +399,17 @@ UIConversation.prototype = {
+@@ -403,16 +403,17 @@ UIConversation.prototype = {
this._observers = this._observers.filter(function(o) o !== aObserver);
},
notifyObservers: function(aSubject, aTopic, aData) {
@@ -97,7 +99,7 @@ diff --git a/chat/components/src/imConversations.js b/chat/components/src/imConv
if (!this.isChat || aSubject.containsNick)
++this._unreadTargetedMessageCount;
}
-@@ -426,16 +427,20 @@ UIConversation.prototype = {
+@@ -430,16 +431,21 @@ UIConversation.prototype = {
if (aSubject.incoming && !aSubject.system &&
(!this.isChat || aSubject.containsNick)) {
this.notifyObservers(aSubject, "new-directed-incoming-message", aData);
@@ -106,8 +108,9 @@ diff --git a/chat/components/src/imConversations.js b/chat/components/src/imConv
}
},
-+ // Called above when the conversation service itself is set as the
-+ // conversation for a message. This is case for some system messages.
++ // Used above when notifying of new-texts originating in the
++ // UIConversation. The happens when this.systemMessage() is called. The
++ // conversation for the message is set as the UIConversation.
+ prepareForDisplaying: function(aMsg) {},
+
// prplIConvIM
@@ -142,7 +145,7 @@ diff --git a/chat/modules/jsProtoHelper.jsm b/chat/modules/jsProtoHelper.jsm
diff --git a/chat/protocols/irc/irc.js b/chat/protocols/irc/irc.js
--- a/chat/protocols/irc/irc.js
+++ b/chat/protocols/irc/irc.js
-@@ -129,16 +129,20 @@ const GenericIRCConversation = {
+@@ -126,16 +126,20 @@ const GenericIRCConversation = {
getMaxMessageLength: function() {
// Build the shortest possible message that could be sent to other users.
let baseMessage = ":" + this._account._nickname + this._account.prefix +
@@ -163,13 +166,13 @@ diff --git a/chat/protocols/irc/irc.js b/chat/protocols/irc/irc.js
// Attempt to smartly split a string into multiple lines (based on the
// maximum number of characters the message can contain).
-@@ -278,24 +282,16 @@ ircChannel.prototype = {
+@@ -274,24 +278,16 @@ ircChannel.prototype = {
_receivedInitialMode: false,
// For IRC you're not in a channel until the JOIN command is received, open
// all channels (initially) as left.
_left: true,
- // True until successfully joined for the first time.
- _firstJoin: false,
+ // True while we are rejoining a channel previously parted by the user.
+ _rejoined: false,
banMasks: [],
- // Overwrite the writeMessage function to apply CTCP formatting before
@@ -188,7 +191,7 @@ diff --git a/chat/protocols/irc/irc.js b/chat/protocols/irc/irc.js
// Otherwise, fall back to the default part message, if it exists.
let msg = aMessage || this._account.getString("partmsg");
if (msg)
-@@ -599,24 +595,16 @@ function ircConversation(aAccount, aName
+@@ -595,24 +591,16 @@ function ircConversation(aAccount, aName
// Always request the info as it may be out of date.
this._waitingForNick = true;
this.requestBuddyInfo(aName);
@@ -238,7 +241,7 @@ diff --git a/chat/protocols/xmpp/xmpp.jsm b/chat/protocols/xmpp/xmpp.jsm
* owner -> founder
*/
const kRoles = ["outcast", "visitor", "participant", "member", "moderator",
-@@ -255,16 +260,22 @@ const XMPPConversationPrototype = {
+@@ -255,16 +260,23 @@ const XMPPConversationPrototype = {
who = this._account._connection._jid.jid;
if (!who)
who = this._account.name;
@@ -247,7 +250,8 @@ diff --git a/chat/protocols/xmpp/xmpp.jsm b/chat/protocols/xmpp/xmpp.jsm
delete this._typingState;
},
-+ /* Perform entity escaping before displaying the message. */
++ /* Perform entity escaping before displaying the message. We assume incoming
++ messages have already been escaped, and will otherwise be filtered. */
+ prepareForDisplaying: function(aMsg) {
+ if (aMsg.outgoing && !aMsg.system)
+ aMsg.displayMessage = TXTToHTML(aMsg.displayMessage);
@@ -261,7 +265,7 @@ diff --git a/chat/protocols/xmpp/xmpp.jsm b/chat/protocols/xmpp/xmpp.jsm
if (aStanza.attributes["type"] == "error") {
aMsg = _("conversation.error.notDelivered", aMsg);
flags.system = true;
-@@ -889,19 +900,17 @@ const XMPPAccountPrototype = {
+@@ -889,19 +901,17 @@ const XMPPAccountPrototype = {
// Prefer HTML (in <html><body>) and use plain text (<body>) as fallback.
let htmlBody = aStanza.getElement(["html", "body"]);
if (htmlBody)
diff --git a/projects/instantbird/test-transformation-api.patch b/projects/instantbird/test-transformation-api.patch
new file mode 100644
index 0000000..f43fcbc
--- /dev/null
+++ b/projects/instantbird/test-transformation-api.patch
@@ -0,0 +1,367 @@
+# HG changeset patch
+# User Arlo Breault <arlolra at gmail.com>
+# Date 1414370632 25200
+# Sun Oct 26 17:43:52 2014 -0700
+# Node ID 49fc79e39b9c292d182a46aa800135bd65b6c38f
+# Parent 030063bcb41284997f862b9b2d12e93bfc0b121a
+Add tests for new messaging pipeline
+
+ * Tests for bugs 1071166, 1088772, and 983347.
+
+diff --git a/chat/components/public/imIConversationsService.idl b/chat/components/public/imIConversationsService.idl
+--- a/chat/components/public/imIConversationsService.idl
++++ b/chat/components/public/imIConversationsService.idl
+@@ -70,29 +70,31 @@ interface imIConversationsService: nsISu
+ };
+
+ // Because of limitations in libpurple (write_conv is called without context),
+ // there's an implicit contract that whatever message string the conversation
+ // service passes to a protocol, it'll get back as the originalMessage when
+ // "new-text" is notified. This is required for the OTR extensions to work.
+
+ // A cancellable outgoing message. Before handing a message off to a protocol,
+-// the conversation service notifies observers (typically add-ons) of an
+-// outgoing message, which can be transformed or cancelled.
++// the conversation service notifies observers of `preparing-message` and
++// `sending-message` (typically add-ons) of an outgoing message, which can be
++// transformed or cancelled.
+ [scriptable, uuid(4391ba5c-9566-41a9-bb9b-fd0a0a490c2c)]
+ interface imIOutgoingMessage: nsISupports {
+ attribute AUTF8String message;
+ attribute boolean cancelled;
+ readonly attribute prplIConversation conversation;
+ };
+
+ // A cancellable message to be displayed. When the conversation service is
+-// notified of a new-text (ie. an incoming or outgoing message to be displayed),
+-// it in turn notifies observers (again, typically add-ons), which have the
+-// opportunity to swap or cancel the message.
++// notified of a `new-text` (ie. an incoming or outgoing message to be
++// displayed), it in turn notifies observers of `received-message`
++// (again, typically add-ons), which have the opportunity to swap or cancel
++// the message.
+ [scriptable, uuid(3f88cc5c-6940-4eb5-a576-c65770f49ce9)]
+ interface imIMessage: prplIMessage {
+ attribute boolean cancelled;
+ // Holds the sender color for Chats.
+ // Empty string by default, it is set by the conversation binding.
+ attribute AUTF8String color;
+
+ // What eventually gets shown to the user.
+diff --git a/chat/components/src/imConversations.js b/chat/components/src/imConversations.js
+--- a/chat/components/src/imConversations.js
++++ b/chat/components/src/imConversations.js
+@@ -59,16 +59,17 @@ imMessage.prototype = {
+ get containsNick() this.prplMessage.containsNick,
+ get noLog() this.prplMessage.noLog,
+ get error() this.prplMessage.error,
+ get delayed() this.prplMessage.delayed,
+ get noFormat() this.prplMessage.noFormat,
+ get containsImages() this.prplMessage.containsImages,
+ get notification() this.prplMessage.notification,
+ get noLinkification() this.prplMessage.noLinkification,
++ get originalMessage() this.prplMessage.originalMessage,
+ getActions: function(aCount) this.prplMessage.getActions(aCount || {})
+ };
+
+ function UIConversation(aPrplConversation)
+ {
+ this._prplConv = {};
+ this.id = ++gLastUIConvId;
+ this._observers = [];
+@@ -120,17 +121,21 @@ UIConversation.prototype = {
+ _currentTargetId: 0,
+ changeTargetTo: function(aPrplConversation) {
+ let id = aPrplConversation.id;
+ if (this._currentTargetId == id)
+ return;
+
+ if (!(id in this._prplConv)) {
+ this._prplConv[id] = aPrplConversation;
+- aPrplConversation.addObserver(this.observeConv.bind(this, id));
++ // Pass an object here, instead of just a function, because coercion
++ // to an nsIObserver won't happen in the JS tests.
++ aPrplConversation.addObserver({
++ observe: this.observeConv.bind(this, id)
++ });
+ }
+
+ let shouldNotify = this._currentTargetId;
+ this._currentTargetId = id;
+ if (!this.isChat) {
+ let buddy = this.buddy;
+ if (buddy)
+ ({statusType: this.statusType, statusText: this.statusText}) = buddy;
+@@ -356,17 +361,17 @@ UIConversation.prototype = {
+
+ // Protocols have an opportunity here to preprocess messages before they are
+ // sent (eg. split long messages). If a message is split here, the split
+ // will be visible in the UI.
+ let messages = this.target.prepareForSending(om);
+
+ // Protocols can return null if they don't need to make any changes.
+ // (nb. passing null with retval array results in an empty array)
+- if (!messages.length)
++ if (!messages || !messages.length)
+ messages = [om.message];
+
+ for (let msg of messages) {
+ // Add-ons (eg. OTR) have an opportunity to tweak or cancel the message
+ // at this point.
+ om = new OutgoingMessage(msg, this.target);
+ this.notifyObservers(om, "sending-message");
+ if (om.cancelled)
+diff --git a/chat/components/src/test/test_conversations.js b/chat/components/src/test/test_conversations.js
+new file mode 100644
+--- /dev/null
++++ b/chat/components/src/test/test_conversations.js
+@@ -0,0 +1,235 @@
++/* Any copyright is dedicated to the Public Domain.
++ * http://creativecommons.org/publicdomain/zero/1.0/ */
++
++const Cu = Components.utils;
++Cu.import("resource:///modules/imServices.jsm");
++Cu.import("resource:///modules/jsProtoHelper.jsm");
++
++let imConversations = {};
++Services.scriptloader.loadSubScript(
++ "resource:///components/imConversations.js", imConversations
++);
++
++// Fake prplConversation
++let _id = 0;
++function Conversation(aName) {
++ this._name = aName;
++ this._observers = [];
++ this._date = Date.now() * 1000;
++ this.id = ++_id;
++}
++Conversation.prototype = {
++ __proto__: GenericConvIMPrototype,
++ _account: {
++ imAccount: {
++ protocol: {name: "Fake Protocol"},
++ alias: "",
++ name: "Fake Account"
++ },
++ ERROR: function(e) {throw e;}
++ }
++};
++
++// Ensure that when iMsg.message is set to a message (including the empty
++// string), it returns that message. If not, it should return the original
++// message. This prevents regressions due to JS coercions.
++let test_null_message = function() {
++ let originalMessage = "Hi!";
++ let pMsg = new Message("buddy", originalMessage, {
++ outgoing: true, _alias: "buddy", time: Date.now()
++ });
++ let iMsg = new imConversations.imMessage(pMsg);
++ equal(iMsg.message, originalMessage);
++ // Setting the message should prevent a fallback to the original.
++ iMsg.message = "";
++ equal(iMsg.message, "");
++ equal(iMsg.originalMessage, originalMessage);
++};
++
++// ROT13, used as an example transformation.
++function rot13(aString) {
++ return aString.replace(/[a-zA-Z]/g, function(c) {
++ return String.fromCharCode(c.charCodeAt(0) + (c.toLowerCase() < "n" ? 1 : -1) * 13);
++ });
++}
++
++// A test that exercises the message transformation pipeline.
++//
++// From the sending users perspective, this looks like:
++// -> UIConv sendMsg
++// -> UIConv notifyObservers `preparing-message`
++// -> protocol prepareForSending
++// -> UIConv notifyObservers `sending-message`
++// -> protocol sendMsg
++// -> protocol writeMessage
++// -> protocol notifyObservers `new-text`
++// -> UIConv notifyObservers `received-message`
++// -> protocol prepareForDisplaying
++// -> UIConv notifyObservers `new-text`
++//
++// From the receiving users perspective, they get:
++// -> protocol writeMessage
++// -> protocol notifyObservers `new-text`
++// -> UIConv notifyObservers `received-message`
++// -> protocol prepareForDisplaying
++// -> UIConv notifyObservers `new-text`
++//
++// The test walks the sending path, which covers both.
++let test_message_transformation = function() {
++ let conv = new Conversation();
++ conv.sendMsg = function(aMsg) {
++ this.writeMessage("user", aMsg, {outgoing: true});
++ };
++
++ let uiConv = new imConversations.UIConversation(conv);
++ let message = "Hello!";
++ let receivedMsg = false, newTxt = false;
++
++ uiConv.addObserver({
++ observe: function(aObject, aTopic, aMsg) {
++ switch(aTopic) {
++ case "sending-message":
++ ok(!newTxt);
++ ok(!receivedMsg);
++ ok(aObject instanceof imConversations.OutgoingMessage);
++ aObject.message = rot13(aObject.message);
++ break;
++ case "received-message":
++ ok(!newTxt);
++ ok(!receivedMsg);
++ ok(aObject.outgoing);
++ ok(aObject instanceof imConversations.imMessage);
++ equal(aObject.displayMessage, rot13(message));
++ aObject.displayMessage = rot13(aObject.displayMessage);
++ receivedMsg = true;
++ break;
++ case "new-text":
++ ok(!newTxt);
++ ok(receivedMsg);
++ ok(aObject.outgoing);
++ ok(aObject instanceof imConversations.imMessage);
++ equal(aObject.displayMessage, message);
++ newTxt = true;
++ break;
++ }
++ }
++ });
++ uiConv.sendMsg(message);
++
++ ok(newTxt);
++};
++
++// A test that cancels a message before it can be sent.
++let test_cancel_send_message = function() {
++ let conv = new Conversation();
++ conv.sendMsg = function(aMsg) {
++ ok(false);
++ };
++
++ let uiConv = new imConversations.UIConversation(conv);
++ uiConv.addObserver({
++ observe: function(aObject, aTopic, aMsg) {
++ if (aTopic === "sending-message") {
++ ok(aObject instanceof imConversations.OutgoingMessage);
++ aObject.cancelled = true;
++ }
++ }
++ });
++ uiConv.sendMsg("Hi!");
++};
++
++// A test that cancels a message before it gets displayed.
++let test_cancel_display_message = function() {
++ let conv = new Conversation();
++ conv.sendMsg = function(aMsg) {
++ this.writeMessage("user", aMsg, {outgoing: true});
++ };
++
++ let uiConv = new imConversations.UIConversation(conv);
++ uiConv.addObserver({
++ observe: function(aObject, aTopic, aMsg) {
++ switch(aTopic) {
++ case "received-message":
++ ok(aObject instanceof imConversations.imMessage);
++ aObject.cancelled = true;
++ break;
++ case "new-text":
++ ok(false);
++ break;
++ }
++ }
++ });
++ uiConv.sendMsg("Hi!");
++};
++
++// A test that ensures protocols get a chance to prepare a message before
++// sending and displaying.
++let test_prpl_message_prep = function() {
++ let conv = new Conversation();
++ conv.sendMsg = function(aMsg) {
++ this.writeMessage("user", aMsg, {outgoing: true});
++ };
++
++ let msg = "Hi!";
++ let prefix = "test> ";
++
++ let prepared = false;
++ conv.prepareForSending = function(aMsg) {
++ ok(aMsg instanceof imConversations.OutgoingMessage);
++ equal(aMsg.message, msg);
++ aMsg.message = prefix + aMsg.message;
++ prepared = true;
++ };
++
++ conv.prepareForDisplaying = function(aMsg) {
++ ok(aMsg instanceof imConversations.imMessage);
++ equal(aMsg.displayMessage, prefix + msg);
++ aMsg.displayMessage = aMsg.displayMessage.slice(prefix.length);
++ };
++
++ let receivedMsg = false;
++ let uiConv = new imConversations.UIConversation(conv);
++ uiConv.addObserver({
++ observe: function(aObject, aTopic, aMsg) {
++ if (aTopic === "new-text") {
++ equal(aObject.displayMessage, msg);
++ receivedMsg = true;
++ }
++ }
++ });
++ uiConv.sendMsg(msg);
++ ok(prepared);
++ ok(receivedMsg);
++};
++
++// A test that ensures protocols can split messages before they are sent.
++let test_split_message_before_sending = function() {
++ let msgCount = 0;
++ let prepared = false;
++
++ let conv = new Conversation();
++ conv.sendMsg = function(aMsg) {
++ ++msgCount;
++ };
++ conv.prepareForSending = function(aMsg) {
++ ok(aMsg instanceof imConversations.OutgoingMessage);
++ prepared = true;
++ return aMsg.message.split("\n");
++ };
++
++ let uiConv = new imConversations.UIConversation(conv);
++ uiConv.sendMsg("This is a looo\nooong message.");
++
++ ok(prepared);
++ equal(msgCount, 2);
++};
++
++function run_test() {
++ test_null_message();
++ test_message_transformation();
++ test_cancel_send_message();
++ test_cancel_display_message();
++ test_prpl_message_prep();
++ test_split_message_before_sending();
++ run_next_test();
++}
+diff --git a/chat/components/src/test/xpcshell.ini b/chat/components/src/test/xpcshell.ini
+--- a/chat/components/src/test/xpcshell.ini
++++ b/chat/components/src/test/xpcshell.ini
+@@ -3,9 +3,10 @@
+ ; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+ [DEFAULT]
+ head =
+ tail =
+
+ [test_accounts.js]
+ [test_commands.js]
++[test_conversations.js]
+ [test_logger.js]
More information about the tor-commits
mailing list