Bug 1316000 - Remove old Yahoo! Messenger support. r=aleth

This commit is contained in:
Patrick Cloke 2016-11-09 10:15:16 -05:00
Родитель 6837d90b95
Коммит 4581f09477
15 изменённых файлов: 20 добавлений и 2171 удалений

Просмотреть файл

@ -86,6 +86,8 @@ pref("chat.xmpp.messageCarbons", true);
pref("chat.prpls.prpl-skype.disable", true);
// Disable Facebook as the XMPP gateway no longer exists.
pref("chat.prpls.prpl-facebook.disable", true);
// Disable Yahoo Messenger as legacy Yahoo was shut down.
pref("chat.prpls.prpl-yahoo.disable", true);
// Whether to disable SRV lookups that use the system DNS library.
pref("chat.dns.srv.disable", false);

Просмотреть файл

@ -2,6 +2,5 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
connection.error.useUsernameNotEmailAddress=Please use your Facebook username, not an email address
facebook.chat.name=Facebook Chat
facebook.disabled=Facebook Chat is no longer supported due to Facebook disabling their XMPP gateway.

Просмотреть файл

@ -2,36 +2,4 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
login.error.badCredentials=Username or password is incorrect.
login.error.accountLockedFailed=Account locked due to too many failed login attempts.
login.error.accountLockedGeneral=Account locked due to too many login attempts.
login.error.accountDeactivated=Account has been deactivated.
login.error.usernameNotExist=The username does not exist.
# The %S will be an error code returned by the server.
login.error.unknown=Unknown error: %S
network.error.http=HTTP connection error.
conference.invite.message=Join my conference.
# Some options are commented out because they aren't used. We do the same thing
# to their description strings.
options.pagerPort=Port
options.transferHost=File transfer server
options.transferPort=File transfer port
options.chatEncoding=Encoding
options.ignoreInvites=Ignore conference invitations
# In this message, %S is replaced with the username of the user who left.
system.message.conferenceLogoff=%S has left the conference.
system.message.conferenceLogon=%S has joined the conference.
# LOCALZIATION NOTE (command.*):
# These are the help messages for each command, the %S is the command name
# Each command first gives the parameter it accepts and then a description of
# the command.
command.help.invite2=%S <user1>[,<user2>,...] [<invite message>]: invite one or more users into this conference chat.
command.help.conference=%S: Create a new conference room in which you can later invite other users.
# LOCALIZATION NOTE (command.feedback.invite):
# %S is the user, or comma separated list of users, invited to the conference.
command.feedback.invite=You have invited %S to the conference.
yahoo.disabled=Yahoo Messenger is no longer supported due to Yahoo disabling their legacy protocol.

Просмотреть файл

@ -6,33 +6,27 @@ var {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/imXPCOMUtils.jsm");
Cu.import("resource:///modules/jsProtoHelper.jsm");
Cu.import("resource:///modules/xmpp.jsm");
Cu.import("resource:///modules/xmpp-session.jsm");
XPCOMUtils.defineLazyGetter(this, "_", () =>
l10nHelper("chrome://chat/locale/facebook.properties")
);
XPCOMUtils.defineLazyGetter(this, "_irc", () =>
l10nHelper("chrome://chat/locale/irc.properties")
);
function FacebookAccount(aProtoInstance, aImAccount) {
this._init(aProtoInstance, aImAccount);
}
FacebookAccount.prototype = {
__proto__: XMPPAccountPrototype,
get canJoinChat() { return false; },
__proto__: GenericAccountPrototype,
connect: function() {
this.WARN("As Facebook deprecated its XMPP gateway, it is currently not " +
"possible to connect to Facebook Chat. See bug 1141674.");
this.reportDisconnecting(Ci.prplIAccount.ERROR_OTHER_ERROR,
_irc("error.unavailable", _("facebook.chat.name")));
_("facebook.disabled"));
this.reportDisconnected();
}
};
function FacebookProtocol() {
}
function FacebookProtocol() {}
FacebookProtocol.prototype = {
__proto__: GenericProtocolPrototype,
get normalizedName() { return "facebook"; },

Просмотреть файл

@ -3,15 +3,9 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
EXTRA_COMPONENTS += [
'yahoo.js',
'yahoo.manifest',
]
EXTRA_JS_MODULES += [
'yahoo-session.jsm',
]
JAR_MANIFESTS += ['jar.mn']

Просмотреть файл

@ -1,98 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource://gre/modules/Services.jsm");
var yahoo = {};
Services.scriptloader.loadSubScript("resource:///components/yahoo.js", yahoo);
function run_test()
{
add_test(test_cleanUsername);
add_test(test_fixFontSize);
run_next_test();
}
// Test the stripping of @yahoo.* domains from usernames.
function test_cleanUsername()
{
// These are just a few of the many possible domains.
let domains = ["yahoo.com.ar", "yahoo.com.au", "yahoo.com", "yahoo.co.jp",
"yahoo.it", "yahoo.cn", "yahoo.co.in"];
let userId = "user";
// We must provide a mimimal fake implementation of a protocol object, to keep
// the YahooAccount constructor happy.
let fakeProtocol = {
id: "fake-proto",
options: {
local_charset: "UTF-8"
},
_getOptionDefault: function(aOption) { return this.options[aOption]; }
};
let fakeImAccount = {};
for (let domain of domains) {
fakeImAccount.name = userId + "@" + domain;
let yahooAccount = new yahoo.YahooAccount(fakeProtocol, fakeImAccount);
do_check_eq(userId, yahooAccount.cleanUsername);
}
run_next_test();
}
// Test the _fixFontSize() method and ensure that it correctly fixes font sizes
// in <font> tags while keeping any mention of size= in conversation untouched.
function test_fixFontSize()
{
// This is an array of two-element arrays. Each inner two-element array
// contains a message with a badly formed font size as the first element,
// and a message with a well-formed font size as the second element. We test
// to ensure that the badly formed message is converted to the well-formed
// one.
let testMessages = [
// Single font tag.
["<font face=\"Arial\" size=\"12\">Test message 1",
"<font face=\"Arial\" size=\"3\">Test message 1"],
// Single font tag with size="<digit>" in innner message.
["<font face=\"Arial\" size=\"9\">size=\"30\" is a big size.</font>",
"<font face=\"Arial\" size=\"2\">size=\"30\" is a big size.</font>"],
// Single font tag with no face attribute.
["<font size=\"12\">This message has no font face attribute.",
"<font size=\"3\">This message has no font face attribute."],
// Single font tag with no size attribute.
["<font face=\"Arial\">This message has no font size attribute.",
"<font face=\"Arial\">This message has no font size attribute."],
// Single font tag with rearranged attribute order.
["<font size=\"9\" face=\"Arial\">size=\"30\" is a big size.</font>",
"<font size=\"2\" face=\"Arial\">size=\"30\" is a big size.</font>"],
// Multiple font tags.
["<font face=\"Arial\" size=\"12\">Hello. <font face=\"Consolas\" size=\"40\">World",
"<font face=\"Arial\" size=\"3\">Hello. <font face=\"Consolas\" size=\"7\">World"]
];
let fakeProtocol = {
id: "fake-proto",
options: {
local_charset: "UTF-8"
},
_getOptionDefault: function(aOption) { return this.options[aOption]; }
};
let fakeImAccount = {name: "test-user"};
// We create a fake conversation object so we can obtain the cleaned up
// message from the conv.writeMessage() call.
let messagePair;
let fakeConversation = {
writeMessage: function(aName, aMessage, aProperties) {
do_check_eq(aMessage, messagePair[1]); // Compare to the good message.
},
updateTyping: function(aStatus, aName) { }
};
let yahooAccount = new yahoo.YahooAccount(fakeProtocol, fakeImAccount);
yahooAccount._conversations.set("test-user", fakeConversation);
for (let pair of testMessages) {
messagePair = pair;
// Send in the badly formed message.
yahooAccount.receiveMessage("test-user", messagePair[0]);
}
run_next_test();
}

Просмотреть файл

@ -1,89 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource:///modules/ArrayBufferUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/yahoo-session.jsm");
var yahoo = {};
Services.scriptloader.loadSubScript("resource:///modules/yahoo-session.jsm", yahoo);
// Preset test values.
var kUsername = "testUser";
var kPassword = "instantbird";
var kPagerIp = "123.456.78.9";
var kCrumb = "MG-Z/jNG+Q==";
var kChallengeString = "AEF08DBAC33F9EEDABCFEA==";
var kYCookie = "OTJmMTQyOTU1ZGQ4MDA3Y2I2ODljMTU5";
var kTCookie = "NTdlZmIzY2Q4ODI3ZTc3NTIxYTk1MDhm";
var kToken = "MThmMzg3OWM3ODcxMW";
var kPagerAddressResponse = "COLO_CAPACITY=1\r\nCS_IP_ADDRESS=" + kPagerIp;
var kTokenResponse = "0\r\n" + kToken + "\r\npartnerid=dummyValue";
var kCookieResponse = "0\r\ncrumb=" + kCrumb + "\r\nY=" + kYCookie +
"\r\nT=" + kTCookie + "\r\ncookievalidfor=86400";
/* In each test, we override the function that would normally be called next in
* the login process. We do this so that we can intercept the login process,
* preventing calls to real Yahoo! servers, and do equality testing. */
function run_test()
{
add_test(test_pagerAddress);
add_test(test_challengeString);
add_test(test_loginToken);
add_test(test_cookies);
run_next_test();
}
function test_pagerAddress()
{
let helper = new yahoo.YahooLoginHelper({}, {});
helper._getChallengeString = function() {
do_check_eq(kPagerIp, helper._session.pagerAddress);
run_next_test();
};
helper._onPagerAddressResponse(kPagerAddressResponse, null);
}
function test_challengeString()
{
let helper = new yahoo.YahooLoginHelper({}, {});
helper._getLoginToken = function() {
do_check_eq(kChallengeString, helper._challengeString);
run_next_test();
};
let response = new yahoo.YahooPacket(yahoo.kPacketType.AuthResponse, 0, 0);
response.addValue(1, helper._username);
response.addValue(94, kChallengeString);
response.addValue(13, 0);
helper._onChallengeStringResponse(response.toArrayBuffer());
}
function test_loginToken()
{
let helper = new yahoo.YahooLoginHelper({}, {});
helper._getCookies = function() {
do_check_eq(kToken, helper._loginToken);
run_next_test();
};
helper._onLoginTokenResponse(kTokenResponse, null);
}
function test_cookies()
{
let helper = new yahoo.YahooLoginHelper({}, {});
helper._sendPagerAuthResponse = function() {
do_check_eq(kCrumb, helper._crumb);
do_check_eq(kYCookie, helper._session.yCookie);
do_check_eq(kTCookie, helper._session.tCookie);
run_next_test();
};
helper._onLoginCookiesResponse(kCookieResponse, null);
}

Просмотреть файл

@ -1,217 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
Components.utils.import("resource:///modules/ArrayBufferUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/yahoo-session.jsm");
var yahoo = {};
Services.scriptloader.loadSubScript("resource:///modules/yahoo-session.jsm", yahoo);
var kPacketIdBytes = StringToBytes(yahoo.kPacketIdentfier);
var kHelloKey = 1;
var kHelloValue = "Hello";
var kWorldKey = 20;
var kWorldValue = "World";
var kNumberKey = 4;
var kNumberValue = 32;
var kParamsKey = 60;
var kParam1Value = "param1";
var kParam2Value = "param2";
var kPacketDataString = "1\xC0\x80Hello\xC0\x8020\xC0\x80World\xC0\x80" +
"4\xC0\x8032\xC0\x8060\xC0\x80param1\xC0\x80" +
"60\xC0\x80param2\xC0\x80";
function run_test()
{
add_test(test_headerCreation);
add_test(test_fullPacketCreation);
add_test(test_packetDecoding);
add_test(test_extractPackets);
add_test(test_malformedPacketExtraction);
run_next_test();
}
function test_headerCreation()
{
let packetLength = 0;
// Random numbers.
let serviceNumber = 0x57;
let status = 0x04;
let sessionId = 0x57842390;
let packet = new yahoo.YahooPacket(serviceNumber, status, sessionId);
let buf = packet.toArrayBuffer();
let view = new DataView(buf);
// Ensure that the first 4 bytes contain the YMSG identifier.
for (let i = 0; i < kPacketIdBytes.length; ++i)
do_check_eq(kPacketIdBytes[i], view.getUint8(i));
do_check_eq(yahoo.kProtocolVersion, view.getUint16(4));
do_check_eq(yahoo.kVendorId, view.getUint16(6));
do_check_eq(packetLength, view.getUint16(8));
do_check_eq(serviceNumber, view.getUint16(10));
do_check_eq(status, view.getUint32(12));
do_check_eq(sessionId, view.getUint32(16));
run_next_test();
}
function test_fullPacketCreation()
{
packetLength = kPacketDataString.length;
// Random numbers.
let serviceNumber = 0x55;
let status = 0x02;
let sessionId = 0x12567800;
let packet = new yahoo.YahooPacket(serviceNumber, status, sessionId);
packet.addValue(kHelloKey, kHelloValue);
packet.addValue(kWorldKey, kWorldValue);
packet.addValue(kNumberKey, kNumberValue);
packet.addValues(kParamsKey, [kParam1Value, kParam2Value]);
let buf = packet.toArrayBuffer();
let view = new DataView(buf);
// Header check.
// Ensure that the first 4 bytes contain the YMSG identifier.
for (let i = 0; i < kPacketIdBytes.length; ++i)
do_check_eq(kPacketIdBytes[i], view.getUint8(i));
do_check_eq(yahoo.kProtocolVersion, view.getUint16(4));
do_check_eq(yahoo.kVendorId, view.getUint16(6));
do_check_eq(packetLength, view.getUint16(8));
do_check_eq(serviceNumber, view.getUint16(10));
do_check_eq(status, view.getUint32(12));
do_check_eq(sessionId, view.getUint32(16));
// Packet data check.
let dataBytes = StringToBytes(kPacketDataString);
for (let i = 0; i < dataBytes.length; ++i)
do_check_eq(dataBytes[i], view.getUint8(yahoo.kPacketHeaderSize + i));
run_next_test()
}
function test_packetDecoding()
{
let packetLength = kPacketDataString.length;
// Random numbers.
let serviceNumber = 0x20;
let status = 0x06;
let sessionId = 0x13319AB2;
let buf = new ArrayBuffer(yahoo.kPacketHeaderSize + packetLength);
let view = new DataView(buf);
for (let i = 0; i < kPacketIdBytes.length; ++i)
view.setUint8(i, kPacketIdBytes[i]);
view.setUint16(4, yahoo.kProtocolVersion);
view.setUint16(6, yahoo.kVendorId);
view.setUint16(8, packetLength);
view.setUint16(10, serviceNumber);
view.setUint32(12, status);
view.setUint32(16, sessionId);
let dataBuf = BytesToArrayBuffer(StringToBytes(kPacketDataString));
copyBytes(buf, dataBuf, 20);
// Now we decode and test.
let packet = new yahoo.YahooPacket();
packet.fromArrayBuffer(buf);
// Test header information.
do_check_eq(serviceNumber, packet.service);
do_check_eq(status, packet.status);
do_check_eq(sessionId, packet.sessionId);
// Test the getting of single packet data values.
do_check_eq(kHelloValue, packet.getValue(kHelloKey));
do_check_eq(kWorldValue, packet.getValue(kWorldKey));
do_check_eq(kNumberValue, packet.getValue(kNumberKey));
// Test the getting of multiple values with a single key.
let multiValue = packet.getValues(kParamsKey);
do_check_eq(2, multiValue.length);
do_check_eq(kParam1Value, multiValue[0]);
do_check_eq(kParam2Value, multiValue[1]);
// Test if certain keys are non-existant.
do_check_true(packet.hasKey(kHelloKey));
do_check_false(packet.hasKey(500)); // There is no key 500.
run_next_test();
}
function test_extractPackets()
{
// Some constants for each packet.
const kP1Service = 0x47;
const kP1Status = 0;
const kP1SessionId = 0x12345678;
// Used for testing packet verification.
const kP1FuzzerKey = 42;
const kP1FuzzerValue = "I am using the YMSG protocol!";
const kP2Service = 0x57;
const kP2Status = 5;
const kP2SessionId = 0x87654321;
// First, create two packets and obtain their buffers.
let packet1 = new yahoo.YahooPacket(kP1Service, kP1Status, kP1SessionId);
packet1.addValue(kHelloKey, kHelloValue);
packet1.addValue(kP1FuzzerKey, kP1FuzzerValue);
let packet1Buffer = packet1.toArrayBuffer();
let packet2 = new yahoo.YahooPacket(kP2Service, kP2Status, kP2SessionId);
packet2.addValue(kWorldKey, kWorldValue);
let packet2Buffer = packet2.toArrayBuffer();
// Create one full buffer with both packets inside.
let fullBuffer = new ArrayBuffer(packet1Buffer.byteLength +
packet2Buffer.byteLength);
copyBytes(fullBuffer, packet1Buffer);
copyBytes(fullBuffer, packet2Buffer, packet1Buffer.byteLength);
// Now, run the packets through the extractPackets() method.
let [extractedPackets, bytesHandled] =
yahoo.YahooPacket.extractPackets(fullBuffer);
do_check_eq(2, extractedPackets.length);
// Packet 1 checks.
let p1 = extractedPackets[0];
do_check_eq(kP1Service, p1.service);
do_check_eq(kP1Status, p1.status);
do_check_eq(kP1SessionId, p1.sessionId);
do_check_true(p1.hasKey(kHelloKey));
do_check_eq(kHelloValue, p1.getValue(kHelloKey));
// Packet 2 checks.
let p2 = extractedPackets[1];
do_check_eq(kP2Service, p2.service);
do_check_eq(kP2Status, p2.status);
do_check_eq(kP2SessionId, p2.sessionId);
do_check_true(p2.hasKey(kWorldKey));
do_check_eq(kWorldValue, p2.getValue(kWorldKey));
// Check if all the bytes were handled.
do_check_eq(fullBuffer.byteLength, bytesHandled);
run_next_test();
}
function test_malformedPacketExtraction()
{
const kInvalidPacketData = "MSYG1\xC0\x80Hello\xC0\x8020\xC0\x80World\xC0\x80";
let buffer = BytesToArrayBuffer(StringToBytes(kInvalidPacketData));
let malformed = false;
try {
yahoo.YahooPacket.extractPackets(buffer);
} catch(e) {
malformed = true;
}
do_check_true(malformed);
run_next_test();
}

Просмотреть файл

@ -1,7 +0,0 @@
[DEFAULT]
head =
tail =
[test_yahooAccount.js]
[test_yahooLoginHelper.js]
[test_yahoopacket.js]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,575 +2,38 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
var {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/imServices.jsm");
Cu.import("resource:///modules/imXPCOMUtils.jsm");
Cu.import("resource:///modules/jsProtoHelper.jsm");
Cu.import("resource:///modules/yahoo-session.jsm");
XPCOMUtils.defineLazyGetter(this, "_", () =>
l10nHelper("chrome://chat/locale/yahoo.properties")
);
// These timeouts are in milliseconds.
var kKeepAliveTimeout = 60 * 1000; // One minute.
var kPingTimeout = 3600 * 1000; // One hour.
function YahooConversation(aAccount, aName)
{
this._buddyUserName = aName;
this._account = aAccount;
this.buddy = aAccount.getBuddy(aName);
this._init(aAccount);
}
YahooConversation.prototype = {
__proto__: GenericConvIMPrototype,
_account: null,
_buddyUserName: null,
_typingTimer: null,
close: function() {
this._account.deleteConversation(this._buddyUserName);
GenericConvChatPrototype.close.call(this);
},
sendMsg: function (aMsg) {
// Deliver the message, then write it to the window.
this._account._session.sendChatMessage(this._buddyUserName,
this._account.encodeMessage(aMsg));
this.finishedComposing();
this.writeMessage(this._account.cleanUsername, aMsg,
{outgoing: true, _alias: this._account.imAccount.alias});
},
sendTyping: function(aString) {
if (aString.length) {
if (!this._typingTimer)
this._account._session.sendTypingStatus(this._buddyUserName, true);
this._refreshTypingTimer();
}
return Ci.prplIConversation.NO_TYPING_LIMIT;
},
finishedComposing: function() {
this._account._session.sendTypingStatus(this._buddyUserName, false);
this._cancelTypingTimer();
},
_refreshTypingTimer: function() {
this._cancelTypingTimer();
this._typingTimer = setTimeout(this.finishedComposing.bind(this), 10000);
},
_cancelTypingTimer: function() {
if (!this._typingTimer)
return;
clearTimeout(this._typingTimer);
delete this._typingTimer
this._typingTimer = null;
},
get name() { return this._buddyUserName; }
};
function YahooConference(aAccount, aRoom, aOwner)
{
this._account = aAccount;
this._roomName = aRoom;
this._owner = aOwner;
this._init(aAccount, aRoom, aAccount.cleanUsername);
}
YahooConference.prototype = {
__proto__: GenericConvChatPrototype,
_account: null,
_roomName: null,
_owner: null,
close: function() {
this.reportLogoff();
this._account.deleteConference(this._roomName);
GenericConvChatPrototype.close.call(this);
},
reportLogoff: function() {
if (this.left)
return;
this._account._session.sendConferenceLogoff(this._account.cleanUsername,
this.getParticipantNames(),
this._roomName);
this.left = true;
},
sendMsg: function(aMsg) {
this._account._session.sendConferenceMessage(this.getParticipantNames(),
this._roomName,
this._account.encodeMessage(aMsg));
},
addParticipant: function(aName) {
// In case we receive multiple conference logon packets, prevent adding
// duplicate buddies.
if (this._participants.get(aName))
return;
let buddy = new YahooConferenceBuddy(aName, this);
this._participants.set(aName, buddy);
this.notifyObservers(new nsSimpleEnumerator([buddy]), "chat-buddy-add");
this.writeMessage(this._roomName,
_("system.message.conferenceLogon", aName),
{system: true});
},
getParticipantNames: function() { return Array.from(this._participants.values()).map(p => p.name); }
};
function YahooConferenceBuddy(aName, aConference)
{
this._name = aName;
this._conference = aConference;
}
YahooConferenceBuddy.prototype = {
__proto__: GenericConvChatBuddyPrototype,
_conference: null,
get founder() { return this._conference._owner == this._name; }
};
function YahooAccountBuddy(aAccount, aBuddy, aTag, aUserName)
{
this._init(aAccount, aBuddy, aTag, aUserName);
}
YahooAccountBuddy.prototype = {
__proto__: GenericAccountBuddyPrototype,
iconChecksum: null,
// This removes the buddy locally, and from the Yahoo! servers.
remove: function() { return this._account.removeBuddy(this, true); },
// This removes the buddy locally, but keeps him on the servers.
removeLocal: function() { return this._account.removeBuddy(this, false); },
createConversation: function() { return this._account.createConversation(this.userName); }
}
function YahooAccount(aProtoInstance, aImAccount)
{
this._init(aProtoInstance, aImAccount);
this._buddies = new Map();
this._conversations = new Map();
this._conferences = new Map();
this._protocol = aProtoInstance;
this._converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
this._converter.charset = this.getString("local_charset") || "UTF-8";
// The username stripped of any @yahoo.* domain.
this.cleanUsername = this.name.replace(/@yahoo\..+$/, "");
}
YahooAccount.prototype = {
__proto__: GenericAccountPrototype,
// YahooSession object passed in constructor.
_session: null,
// A Map holding the list of buddies associated with their usernames.
_buddies: null,
// A Map holding the list of open buddy conversations associated with the
// username of the buddy.
_conversations: null,
// A Map holding the list of open conference rooms associated with the room
// name.
_conferences: null,
// YahooProtocol object passed in the constructor.
_protocol: null,
// An nsIScriptableUnicodeConverter used to convert incoming/outgoing chat
// messages to the correct charset.
_converter: null,
// This is simply incremented by one everytime a new conference room is
// created. It is appened to the end of the room name when a new room is
// created, ensuring name uniqueness.
_roomsCreated: 0,
// The username stripped of any @yahoo.* domain.
cleanUsername: null,
// The timers used to send keepalive and ping packets to the server to ensrue
// the server that the user is still connected.
_keepAliveTimer: null,
_pingTimer: null,
connect: function() {
this._session = new YahooSession(this);
this._session.login(this.imAccount.name, this.imAccount.password);
},
disconnect: function(aSilent) {
// Log out of all of the conferences the user is in.
for (let conf of this._conferences)
conf[1].reportLogoff();
if (this.connected) {
this.reportDisconnecting(Ci.prplIAccount.NO_ERROR, "");
if (this._session.isConnected)
this._session.disconnect();
this.reportDisconnected();
}
// buddy[1] is the actual object.
for (let buddy of this._buddies)
buddy[1].setStatus(Ci.imIStatusInfo.STATUS_UNKNOWN, "");
// Clear and delete the timers to avoid memory leaks.
if (this._keepAliveTimer) {
this._keepAliveTimer.cancel();
delete this._keepAliveTimer;
}
if (this._pingTimer) {
this._pingTimer.cancel();
delete this._pingTimer;
}
},
observe: function(aSubject, aTopic, aData) {
if (aTopic == "status-changed")
this._session.setStatus(aSubject.statusType, aData);
else if (aTopic == "user-icon-changed")
this._session.setProfileIcon(aData);
},
remove: function() {
for (let conv of this._conversations.values())
conv.close();
delete this._conversations;
for (let buddy of this._buddies)
buddy[1].removeLocal(); // buddy[1] is the actual object.
},
unInit: function() {
this.disconnect(true);
delete this.imAccount;
},
createConversation: function(aName) {
let conv = new YahooConversation(this, aName);
this._conversations.set(aName, conv);
return conv;
},
deleteConversation: function(aName) {
if (this._conversations.has(aName))
this._conversations.delete(aName);
},
receiveConferenceInvite: function(aOwner, aRoom, aParticipants, aMessage) {
// Do nothing if we wish to ignore invites.
if (!Services.prefs.getIntPref("messenger.conversations.autoAcceptChatInvitations") ||
this.getBool("ignore_invites"))
return;
let conf = new YahooConference(this, aRoom, aOwner);
this._conferences.set(aRoom, conf);
for (let participant of aParticipants)
conf.addParticipant(participant);
// Add ourselves to the conference room as well.
conf.addParticipant(this.imAccount.name);
this._session.acceptConferenceInvite(aOwner, aRoom,
conf.getParticipantNames());
},
receiveConferenceLogon: function(aRoom, aUsername) {
if (!this._conferences.has(aRoom))
return;
let conf = this._conferences.get(aRoom);
conf.addParticipant(aUsername);
},
receiveConferenceLogoff: function(aRoom, aUsername) {
if (!this._conferences.has(aRoom))
return;
let conf = this._conferences.get(aRoom);
conf.removeParticipant(aUsername);
conf.writeMessage(this._roomName,
_("system.message.conferenceLogoff", aName),
{system: true});
},
deleteConference: function(aName) {
if (this._conferences.has(aName))
this._conferences.delete(aName);
},
// Called when the user adds or authorizes a new contact.
addBuddy: function(aTag, aName) {
let buddy = new YahooAccountBuddy(this, null, aTag, aName);
this._buddies.set(buddy.userName, buddy);
this._session.addBuddyToServer(buddy);
Services.contacts.accountBuddyAdded(buddy);
},
hasBuddy: function(aName) {
return this._buddies.has(aName);
},
// Called for each buddy that is sent in a list packet from Yahoo! on login.
addBuddyFromServer: function(aTag, aName) {
let buddy;
if (this._buddies.has(aName))
buddy = this._buddies.get(aName);
else {
buddy = new YahooAccountBuddy(this, null, aTag, aName);
Services.contacts.accountBuddyAdded(buddy);
this._buddies.set(aName, buddy);
}
// Set all new buddies as offline because a following status packet will
// tell their status if they are online.
buddy.setStatus(Ci.imIStatusInfo.STATUS_OFFLINE, "");
// Request the buddy's picture.
this._session.requestBuddyIcon(aName);
},
// Called when a user removes a contact from within Instantbird.
removeBuddy: function(aBuddy, aRemoveFromServer) {
if (aRemoveFromServer) {
// We will remove the buddy locally when we get a server ack packet.
this._session.removeBuddyFromServer(aBuddy);
return;
}
this._buddies.delete(aBuddy.userName);
Services.contacts.accountBuddyRemoved(aBuddy);
},
loadBuddy: function(aBuddy, aTag) {
let buddy = new YahooAccountBuddy(this, aBuddy, aTag);
this._buddies.set(buddy.userName, buddy);
return buddy;
},
// Both the status and message can be defined, or only one can be defined.
// When defining just the message, set aStatus to undefined.
setBuddyStatus: function(aName, aStatus, aMessage) {
if (!this._buddies.has(aName))
return;
let buddy = this._buddies.get(aName);
// If the message is set as undefined, use the existing message.
if (aMessage === undefined)
aMessage = buddy.statusText;
// If the status is undefined, use the existing status.
if (aStatus === undefined)
aStatus = buddy.statusType;
buddy.setStatus(aStatus, aMessage);
},
getBuddy: function(aName) {
if (this._buddies.has(aName))
return this._buddies.get(aName);
return null;
},
getOnlineBuddies: function() {
let onlineBuddies = [];
for (let buddy of this._buddies) {
if (buddy[1].statusType != Ci.imIStatusInfo.STATUS_OFFLINE)
onlineBuddies.push(buddy[1]);
}
return onlineBuddies;
},
receiveMessage: function(aName, aMessage) {
let conv;
// Check if we have an existing converstaion open with this user. If not,
// create one and add it to the list.
if (!this._conversations.has(aName))
conv = this.createConversation(aName);
else
conv = this._conversations.get(aName);
// Certain Yahoo clients, such as the official web client, sends formatted
// messages, but the size value is the actual pt size, not the 1 - 7 size
// expected from the HTML <font> tag. We replace it with the correct size.
let message = this.decodeMessage(aMessage)
.replace(/(<font[^>]+)size=\"(\d+)\"/g, this._fixFontSize);
conv.writeMessage(aName, message, {incoming: true});
conv.updateTyping(Ci.prplIConvIM.NOT_TYPING, conv.name);
},
receiveConferenceMessage: function(aName, aRoom, aMessage) {
if (!this._conferences.has(aRoom))
return;
this._conferences.get(aRoom).writeMessage(aName,
this.decodeMessage(aMessage),
{incoming: true});
},
receiveTypingNotification: function(aName, aIsTyping) {
if (!this._conversations.has(aName))
return;
let conv = this._conversations.get(aName);
if (aIsTyping)
conv.updateTyping(Ci.prplIConvIM.TYPING, conv.name);
else
conv.updateTyping(Ci.prplIConvIM.NOT_TYPING, conv.name);
},
encodeMessage: function(aMessage) {
// Try to perform a convertion from JavaScript UTF-16 into the charset
// specified in the options. If the conversion fails, just leave
// the message as it is.
let encodedMsg;
try {
encodedMsg = this._converter.ConvertFromUnicode(aMessage);
} catch (e) {
encodedMsg = aMessage;
this.WARN("Could not encode UTF-16 message into " +
this._converter.charset + ". Message: " + aMessage);
}
return encodedMsg;
},
decodeMessage: function(aMessage) {
// Try to perform a convertion from the charset specified in the options
// to JavaScript UTF-16. If the conversion fails, just leave the message
// as it is.
let decodedMsg;
try {
decodedMsg = this._converter.ConvertToUnicode(aMessage);
} catch (e) {
decodedMsg = aMessage;
this.WARN("Could not decode " + this._converter.charset +
" message into UTF-16. Message: " + aMessage);
}
return decodedMsg;
},
get canJoinChat() { return true; },
chatRoomFields: {},
joinChat: function(aComponents) {
// Use _roomsCreated to append a unique number to the room name.
let roomName = this.cleanUsername + "-" + ++this._roomsCreated;
let conf = new YahooConference(this, roomName, this.cleanUsername);
this._conferences.set(roomName, conf);
this._session.createConference(roomName);
},
// Callbacks.
onLoginComplete: function() {
// Now that we are connected, get ready to start to sending pings and
// keepalive packets.
this._keepAliveTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
this._pingTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
// We use slack timers since we don't need millisecond precision when
// sending the keepalive and ping packets.
let s = this._session;
this._keepAliveTimer
.initWithCallback(s.sendKeepAlive.bind(s), kKeepAliveTimeout,
this._keepAliveTimer.TYPE_REPEATING_SLACK);
this._pingTimer
.initWithCallback(s.sendPing.bind(s), kPingTimeout,
this._pingTimer.TYPE_REPEATING_SLACK);
},
// Private methods.
// This method is used to fix font sizes given by formatted messages. This
// method is designed to be used as a method for a string replace() call.
_fixFontSize: function(aMatch, aTagAttributes, aFontSize, aOffset, aString) {
// Approximate the font size.
let newSize;
if (aFontSize <= 8)
newSize = "1";
else if (aFontSize <= 10)
newSize = "2";
else if (aFontSize <= 12)
newSize = "3";
else if (aFontSize <= 14)
newSize = "4";
else if (aFontSize <= 20)
newSize = "5";
else if (aFontSize <= 30)
newSize = "6";
else if (aFontSize <= 40)
newSize = "7";
else // If we get some gigantic size, just default to the standard 3 size.
newSize = "3";
let sizeAttribute = "size=\"" + newSize + "\"";
// We keep any preceding attributes, but replace the size attribute.
return aTagAttributes + sizeAttribute;
this.WARN("The legacy versions of Yahoo Messenger was disabled on August " +
"5, 2016. It is currently not possible to connect to Yahoo " +
"Messenger. See bug 1316000");
this.reportDisconnecting(Ci.prplIAccount.ERROR_OTHER_ERROR,
_("yahoo.disabled"));
this.reportDisconnected();
}
};
function YahooProtocol() {
this.registerCommands();
}
function YahooProtocol() {}
YahooProtocol.prototype = {
__proto__: GenericProtocolPrototype,
// Protocol specific connection parameters.
pagerRequestUrl: "http://scsa.msg.yahoo.com/capacity",
loginTokenGetUrl: "https://login.yahoo.com/config/pwtoken_get",
loginTokenLoginUrl: "https://login.yahoo.com/config/pwtoken_login",
buildId: "4194239",
get id() { return "prpl-yahoo"; },
get name() { return "Yahoo"; },
get iconBaseURI() { return "chrome://prpl-yahoo/skin/"; },
options: {
port: {get label() { return _("options.pagerPort"); }, default: 5050},
local_charset: {get label() { return _("options.chatEncoding"); }, default: "UTF-8"},
ignore_invites: {get label() { return _("options.ignoreInvites"); }, default: false}
},
commands: [
{
name: "invite",
get helpString() { return _("command.help.invite2", "invite"); },
usageContext: Ci.imICommand.CMD_CONTEXT_ALL,
run: function(aMsg, aConv) {
if (aMsg.trim().length == 0)
return false;
let splitPosition = aMsg.indexOf(" "); // Split at first space.
let invitees;
let message;
// If we have an invite message.
if (splitPosition > 0) {
invitees = aMsg.substring(0, splitPosition).split(",");
message = aMsg.substring(splitPosition);
} else {
invitees = aMsg.split(",");
message = _("conference.invite.message"); // Use default message.
}
let conf = aConv.wrappedJSObject;
conf._account._session.inviteToConference(invitees, conf._roomName,
conf.getParticipantNames(),
message);
conf.writeMessage(conf._roomName,
_("command.feedback.invite", invitees.join(", ")),
{system: true, noLog: true});
conf._account.LOG("Sending conference invite to " + invitees);
return true;
},
},
{
name: "conference",
get helpString() { return _("command.help.conference", "conference"); },
usageContext: Ci.imICommand.CMD_CONTEXT_CHAT,
run: function(aMsg, aConv) {
aConv.account.joinChat(null);
return true;
}
}
],
getAccount: function(aImAccount) { return new YahooAccount(this, aImAccount); },
classID: Components.ID("{50ea817e-5d79-4657-91ae-aa0a52bdb98c}")
};

Просмотреть файл

@ -342,8 +342,7 @@
msg = "<font face=\"" + style.fontFamily + "\">" + msg + "</font>";
// MSN doesn't support font size info in messages...
}
else if (proto == "prpl-aim" || proto == "prpl-icq" ||
proto == "prpl-yahoo" || proto == "prpl-yahoojp") {
else if (proto == "prpl-aim" || proto == "prpl-icq") {
let styleAttributes = ""
if ("color" in style)
styleAttributes += " color=\"" + style.color + "\"";

Просмотреть файл

@ -8,7 +8,7 @@
# Exceeding 4 protocols may cause scrolling. A list of the
# available protocols can be found at
# https://wiki.instantbird.org/Protocol_Identifiers
topProtocol.list=prpl-gtalk,prpl-twitter,prpl-aim,prpl-yahoo,prpl-irc
topProtocol.list=prpl-gtalk,prpl-twitter,prpl-aim,prpl-irc,prpl-xmpp
# LOCALIZATION NOTE
# These are the descriptions of the top protocols specified above.
@ -16,5 +16,5 @@ topProtocol.list=prpl-gtalk,prpl-twitter,prpl-aim,prpl-yahoo,prpl-irc
topProtocol.prpl-gtalk.description=Talk to your Gmail contacts
topProtocol.prpl-twitter.description=Stay up to date with your Twitter timeline
topProtocol.prpl-aim.description=Chat with your buddies on AOL Instant Messenger
topProtocol.prpl-yahoo.description=Chat with friends using Yahoo! Messenger
topProtocol.prpl-irc.description=Join IRC channels
topProtocol.prpl-xmpp.description=Chat using the open Jabber/XMPP protocol

Просмотреть файл

@ -7,5 +7,4 @@
[include:chat/protocols/irc/test/xpcshell.ini]
[include:chat/protocols/skype/test/xpcshell.ini]
[include:chat/protocols/xmpp/test/xpcshell.ini]
[include:chat/protocols/yahoo/test/xpcshell.ini]
#[include:extensions/purple/purplexpcom/src/test/xpcshell.ini]

Просмотреть файл

@ -282,8 +282,7 @@
msg = "<font face=\"" + style.fontFamily + "\">" + msg + "</font>";
// MSN doesn't support font size info in messages...
}
else if (proto == "prpl-aim" || proto == "prpl-icq" ||
proto == "prpl-yahoo" || proto == "prpl-yahoojp") {
else if (proto == "prpl-aim" || proto == "prpl-icq") {
let styleAttributes = ""
if ("color" in style)
styleAttributes += " color=\"" + style.color + "\"";