tildefriends/packages/cory/libirc/libirc.js

172 lines
4.6 KiB
JavaScript
Raw Normal View History

"use strict";
//! {
//! "category": "libraries",
//! "permissions": [
//! "network"
//! ],
//! "chat": {
//! "version": 1,
//! "settings": [
//! {"name": "user", "type": "text"},
//! {"name": "realName", "type": "text"},
//! {"name": "password", "type": "password"},
//! {"name": "nick", "type": "text"},
//! {"name": "server", "type": "text"},
//! {"name": "port", "type": "text"},
//! {"name": "autoJoinChannels", "type": "text"}
//! ]
//! },
//! "require": [
//! "libchat"
//! ]
//! }
let ChatService = require("libchat").ChatService;
class IrcService {
constructor(options) {
let self = this;
self._service = new ChatService(options.callback);
self._name = options.name;
self._nick = options.nick;
self._nameReplies = {};
network.newConnection().then(function(socket) {
self._socket = socket;
return self._connect(options);
});
}
_decode(text) {
if (text) {
for (let i = 0; i < text.length; i++) {
if (text.charCodeAt(i) > 128) {
text = text.substring(0, i) + "?" + text.substring(i + 1);
}
}
}
return text;
}
_send(line) {
return this._socket.write(line + "\r\n");
}
_receivedLine(originalLine) {
try {
let line = this._decode(originalLine);
let prefix;
if (line.charAt(0) == ":") {
let space = line.indexOf(" ");
prefix = line.substring(1, space);
line = line.substring(space + 1);
}
let lineNoPrefix = line;
let remainder;
let colon = line.indexOf(" :");
if (colon != -1) {
remainder = line.substring(colon + 2);
line = line.substring(0, colon);
}
let parts = line.split(" ");
if (remainder) {
parts.push(remainder);
}
let conversation = "";
if (parts[0] == "PRIVMSG" || parts[0] == "NOTICE") {
// Is it a channel type?
if ("&#!+.".indexOf(parts[1].charAt(0)) != -1) {
conversation = parts[1];
} else if (prefix.indexOf('!') != -1) {
conversation = prefix.split('!')[0];
}
this._service.notifyMessageReceived(conversation, {
from: prefix.split('!')[0],
message: parts[parts.length - 1],
type: parts[0],
});
} else if (parts[0] == "PING") {
parts[0] = "PONG";
this._send(parts.join(" "));
} else if (parts[0] == "JOIN") {
let person = prefix.split('!')[0];
let conversation = parts[1];
this._service.notifyPresenceChanged(conversation, person, "present");
} else if (parts[0] == "PART") {
let person = prefix.split('!')[0];
let conversation = parts[1];
this._service.notifyPresenceChanged(conversation, person, "unavailable");
} else if (parts[0] == "353") { // RPL_NAMREPLY
if (!this._nameReplies[parts[3]]) {
this._nameReplies[parts[3]] = [];
}
let users = parts[4].split(' ');
for (let i in users) {
let user = users[i];
let state = "present";
if ("@+".indexOf(user.charAt(0)) != -1) {
state = user.charAt(0);
user = user.substring(1);
}
this._nameReplies[parts[3]][user] = state;
}
} else if (parts[0] == "366") { // RPL_ENDOFNAMES
for (let conversation in this._nameReplies) {
this._service.notifyParticipantList(conversation, this._nameReplies[conversation]);
}
this._nameReplies = {};
} else {
this._service.notifyMessageReceived("", {from: prefix, message: lineNoPrefix});
}
} catch (error) {
this._service.reportError(error);
}
}
_connect(options) {
let self = this;
let readBuffer = "";
self._socket.read(function(data) {
if (data) {
readBuffer += data;
let end = readBuffer.indexOf("\n");
while (end != -1) {
let line = readBuffer.substring(0, end);
if (line.charAt(line.length - 1) == "\r") {
line = line.substring(0, line.length - 1);
}
readBuffer = readBuffer.substring(end + 1);
self._receivedLine(line);
end = readBuffer.indexOf("\n");
}
} else {
self._service.notifyStateChanged("disconnected");
}
});
return self._socket.connect(options.server, options.port).then(function() {
self._service.notifyStateChanged("connected");
self._send("USER " + options.user + " 0 * :" + options.realName);
self._send("NICK " + options.nick);
}).catch(self._service.reportError);
}
sendMessage(target, text) {
if (!target) {
this._socket.write(text + "\r\n");
} else {
this._socket.write("PRIVMSG " + target + " :" + text + "\r\n");
}
this._service.notifyMessageReceived(target || "", {from: this._nick, message: text, timestamp: new Date().toString()});
}
disconnect() {
this._send("QUIT");
this._socket.close();
this._service.notifyStateChanged("disconnected");
}
};
ChatService.handleMessages(IrcService);