Permalink
Browse files

lots more changes

  • Loading branch information...
1 parent 14219d1 commit 1a7b16d28e250684d830c11bf48001d7fd01715f @kkaefer committed Jan 14, 2011
Showing with 283 additions and 92 deletions.
  1. +6 −1 config.js
  2. +11 −3 lib/helper.js
  3. +46 −8 lib/ircd.js
  4. +33 −25 lib/xmpp.js
  5. +187 −55 medium.js
View
@@ -2,9 +2,14 @@ exports.xmpp = {
// host: 'jabber.org',
// jid: 'jabber.org',
// muc: 'conference.jabber.org'
+
host: 'localhost',
jid: 'localhost',
- muc: 'conference.localhost'
+ muc: 'conference.localhost',
+
+ host: 'chat.developmentseed.org',
+ jid: 'chat.developmentseed.org',
+ muc: 'conference.chat.developmentseed.org'
};
exports.irc = {
View
@@ -39,14 +39,22 @@ exports.xmlFind = function find(xml, name) {
exports.xmlPath = function path(xml, path) {
path = path.split('.');
+ xml = [ xml ];
for (var k = 0; k < path.length; k++) {
- for (var i = 0; i < xml.length; i++) {
- if (xml[i].$name === path[k]) xml = xml[i];
+ var elements = [];
+ for (var j = 0; j < xml.length; j++) {
+ for (var i = 0; i < xml[j].length; i++) {
+ if (xml[j][i].$name === path[k]) {
+ elements.push(xml[j][i]);
+ }
+ }
}
+ if (elements.length) xml = elements;
+ else return;
}
- return xml;
+ return xml[0];
};
exports.xml.auth = exports.xml.$.bind(undefined, 'auth');
View
@@ -60,10 +60,23 @@ Connection.prototype.setup = function() {
}
}
});
+
+ this.stream.on('end', function() { connection.emit('end'); });
+ this.stream.on('close', function() { connection.emit('close'); });
};
Connection.prototype.end = function() {
- this.stream.end();
+ switch (this.stream.readyState) {
+ case 'writeOnly': // The other party disconnected the stream already.
+ case 'open':
+ case 'opening':
+ this.stream.end();
+ break;
+ case 'readOnly': // We already ended the stream.
+ case 'closed': // The stream is already closed.
+ // Nothing to do.
+ break;
+ }
};
Connection.prototype.PASS = function(pass) {
@@ -89,6 +102,7 @@ Connection.prototype.USER = function(line) {
this.reply('003', ':This server was created ' + this.config.created);
this.reply('004', this.config.host + ' ' + this.config.name + '-' + this.config.version + ' ');
+ this.loggedIn = true;
this.emit('login');
};
@@ -100,7 +114,11 @@ Connection.prototype.JOIN = function(line) {
// Discard optional password.
var channel = line.split(' ', 1)[0];
var rest = line.substring(channel.length + 1);
- this.emit('join', channel, rest);
+
+ var channels = channel.split(',');
+ for (var i = 0; i < channels.length; i++) {
+ this.emit('join', channels[i], rest);
+ }
};
Connection.prototype.MODE = function(line) {
@@ -112,38 +130,58 @@ Connection.prototype.MODE = function(line) {
Connection.prototype.PRIVMSG = function(line) {
var recipient = line.split(' ', 1)[0];
var message = line.substring(recipient.length + 1);
+ if (message[0] === ':') message = message.substring(1);
this.emit('privmsg', recipient, message);
};
Connection.prototype.PART = function(line) {
var channel = line.split(' ', 1)[0];
this.emit('part', channel);
-}
+};
Connection.prototype.PONG = function(line) {
this.emit('pong', line);
};
+Connection.prototype.QUIT = function(line) {
+ this.emit('quit', line);
+};
+
Connection.prototype.reply = function(code, msg) {
var str = ':' + this.config.name + ' ' + code + ' ' + this.user.nick + ' ' + msg + '\r\n';
console.log(GREEN('IRC out>> ' + util.inspect(str)));
this.stream.write(str);
};
+Connection.prototype.error = function(msg) {
+ var str = 'ERROR :' + msg + '\r\n';
+ console.log(GREEN('IRC out>> ' + util.inspect(str)));
+ this.stream.write(str);
+};
+
Connection.prototype.command = function(cmd, msg, user) {
var str = ':' + (user || (this.user.nick + '!' + this.user.user)) + ' ' + cmd + ' ' + msg + '\r\n';
console.log(GREEN('IRC out>> ' + util.inspect(str)));
this.stream.write(str);
-}
+};
+
exports.sanitizeNick = function(str) {
- var nick = str.replace(/([^\x30-\x7D-]|@)+/g, '_');
- if (nick.match(/^[\x5B-\x60\x7B-\x7D-]/)) nick = '_' + nick;
- return nick;
+ // This is how it should be according to RFC:
+ // return str.replace(/([^\x30-\x7D-]|@)+/g, '_');
+
+ // Most clients support UTF-8, however, so we just strip control characters.
+ // We replace spaces with a non-breaking space because they really aren't allowed.
+ return str.replace(/ /g, '\u00A0').replace(/[\x00-\x2F@]+/g, '_');
};
exports.sanitizeUser = function(str) {
return str.replace(/[\0\r\n @]+/g, '_');
-}
+};
+
+exports.sanitizeMessage = function(str) {
+ return str.replace(/\r?\n/g, ' ');
+};
+
View
@@ -95,19 +95,12 @@ Connection.prototype.createParser = function() {
cb.onEndElementNS(function(elem, prefix, uri) {
var element = tree.shift();
if (tree.length === 1) {
- // if (element.$name === 'iq' && ) {
- // xml.$render(xml.iq({ from: element.to, to: element.from, id: element.id, type: 'result' }));
- // }
- // else
if (element.id && (element.id in self.requests)) {
// If the response has an ID associated with it, call the corresponding
// function supplied when placing the request.
var command = self.requests[element.id];
command.call(self, element);
}
- // else if (element.$name in self) {
- // self[element.$name](element);
- // }
else {
self.emit(element.$name, element);
}
@@ -121,27 +114,27 @@ Connection.prototype.setupStream = function() {
this.stream = net.createConnection(this.config.port, this.config.host);
this.stream.setEncoding('ascii');
+ this.stream.on('error', function(err) { self.emit('error'); });
this.stream.on('connect', function() { self.initStream(); });
this.stream.on('secure', function() { self.initStream(); });
this.stream.on('data', function(str) {
console.log(BLUE('in <- ' + str));
self.parser.parseString(str);
});
+ this.stream.on('end', function() { self.emit('end'); });
+ this.stream.on('close', function() { self.emit('close'); });
};
Connection.prototype.setupHandlers = function() {
- this.on('error', function(error) {
- console.log(error);
- });
-
this.once('features', function(features) {
if (find(features, 'starttls').length)
this.startTLS();
- else
+ else {
this.emit('error', 'Server does not support STARTTLS.');
// DEBUG: Proceed anyway without SSL!
this.detectFeatures(features);
+ }
});
};
@@ -204,10 +197,20 @@ Connection.prototype.authenticate = function(user) {
};
Connection.prototype.end = function() {
- console.log(PURPLE('out -> ' + '</stream:stream>'));
- this.stream.write('</stream:stream>');
- this.stream.end();
-}
+ switch (this.stream.readyState) {
+ case 'writeOnly': // The other party disconnected the stream already.
+ case 'open':
+ case 'opening':
+ console.log(PURPLE('out -> ' + '</stream:stream>'));
+ this.stream.end('</stream:stream>');
+ break;
+ case 'readOnly': // We already ended the stream.
+ case 'closed': // The stream is already closed.
+ // Nothing to do.
+ break;
+
+ }
+};
Connection.prototype.request = function(stanza, callback) {
var id = 'medium' + (this.uniqueID++);
@@ -232,7 +235,7 @@ Connection.prototype.bind = function() {
this.request(
xml.iq({ type: 'set' }, xml.bind({ xmlns: 'urn:ietf:params:xml:ns:xmpp-bind' })),
function(response) {
- this.user = new JID(path(response, 'iq.bind.jid').$body);
+ this.user = new JID(path(response, 'bind.jid').$body);
this.emit('bind');
}
);
@@ -254,34 +257,39 @@ Connection.prototype.startSession = function() {
Connection.prototype.roomInfo = function(roomJID, callback) {
var query = xml.query({ xmlns: 'http://jabber.org/protocol/disco#info' });
var stanza = xml.iq({ type: 'get', to: roomJID }, query);
- this.request(stanza, callback || noop);
+ this.request(stanza, callback);
};
Connection.prototype.roomItems = function(roomJID, callback) {
var query = xml.query({ xmlns: 'http://jabber.org/protocol/disco#items' });
var stanza = xml.iq({ type: 'get', to: roomJID }, query);
- this.request(stanza, callback || noop);
-}
+ this.request(stanza, callback);
+};
Connection.prototype.roomPresence = function(nickJID, callback) {
var capability = xml.x({ xmlns: 'http://jabber.org/protocol/muc' });
var stanza = xml.presence({ to: nickJID }, capability);
- this.request(stanza, callback || noop);
+ this.request(stanza, callback);
};
Connection.prototype.roomMessage = function(roomJID, message, callback) {
var body = xml.body(null, message);
var stanza = xml.message({ to: roomJID, type: 'groupchat' }, body);
- this.request(stanza, callback || noop);
-}
+ this.request(stanza, callback);
+};
Connection.prototype.roomNick = function(nickJID, callback) {
var stanza = xml.presence({ to: nickJID });
- this.request(stanza, callback || noop);
+ this.request(stanza, callback);
};
Connection.prototype.leaveRoom = function(roomJID) {
var stanza = xml.presence({ to: roomJID, type: 'unavailable' });
this.request(stanza);
-}
+};
+Connection.prototype.userMessage = function(userJID, message, callback) {
+ var body = xml.body(null, message);
+ var stanza = xml.message({ to: userJID, type: 'chat' }, body);
+ this.request(stanza, callback);
+};
Oops, something went wrong.

0 comments on commit 1a7b16d

Please sign in to comment.