|
@@ -0,0 +1,373 @@
|
|
|
+var net = require('net');
|
|
|
+
|
|
|
+var IRCserver = require('./server');
|
|
|
+var IRCuser = require('./user');
|
|
|
+var IRCchannel = require('./channel');
|
|
|
+
|
|
|
+var uplink = null;
|
|
|
+var connection = null;
|
|
|
+var recvData = '';
|
|
|
+var users = [];
|
|
|
+var servers = [];
|
|
|
+var channels = [];
|
|
|
+var me = null;
|
|
|
+
|
|
|
+module.exports.setConnection = setConnection;
|
|
|
+
|
|
|
+function findServer(s){
|
|
|
+ for(var i=0; i<servers.length; i++){
|
|
|
+ srv = servers[i];
|
|
|
+ if(srv.sid == s || srv.name == s) return srv;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+}
|
|
|
+
|
|
|
+function findUser(u){
|
|
|
+ for(var i=0; i<users.length; i++){
|
|
|
+ usr = users[i];
|
|
|
+ if(usr.uid == u || usr.name == u) return usr;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+}
|
|
|
+
|
|
|
+function getChannel(name){
|
|
|
+ var lowerName = name.toLowerCase();
|
|
|
+ var channel = null;
|
|
|
+ for(var i=0; i<channels.length; i++){
|
|
|
+ if(channels[i].name == lowerName){
|
|
|
+ channel = channels[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(!channel){
|
|
|
+ console.log('Creating channel '+name);
|
|
|
+ channel = new IRCchannel;
|
|
|
+ channel.name = name;
|
|
|
+ channels.push(channel);
|
|
|
+ }
|
|
|
+ return channel;
|
|
|
+}
|
|
|
+
|
|
|
+function killUser(user){
|
|
|
+ console.log('KILL');
|
|
|
+ console.log(user);
|
|
|
+// TODO
|
|
|
+}
|
|
|
+
|
|
|
+function newUser(nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname, uplink){ // nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname, uplink
|
|
|
+ var user;
|
|
|
+ if((user = findUser(uid)) || (user = findUser(nick))){
|
|
|
+ console.log(user);
|
|
|
+ throw 'User already exists';
|
|
|
+ }
|
|
|
+ console.log('Introducing user '+nick);
|
|
|
+ user = new IRCuser;
|
|
|
+ user.introduce(nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname, uplink);
|
|
|
+ users.push(user);
|
|
|
+}
|
|
|
+
|
|
|
+function newServer(name, sid, desc, distance, uplink){
|
|
|
+ if(findServer(sid) || findServer(name)){
|
|
|
+ throw 'Server already exists';
|
|
|
+ }
|
|
|
+ console.log('Introducing server '+name+' (SID='+sid+', desc="'+desc+'")');
|
|
|
+ server = new IRCserver;
|
|
|
+ server.introduce(name, sid, desc, distance, uplink);
|
|
|
+ servers.push(server);
|
|
|
+}
|
|
|
+
|
|
|
+function parseUmodes(text){
|
|
|
+ return null;
|
|
|
+ // TODO
|
|
|
+}
|
|
|
+
|
|
|
+function setConnection(host, port, protocol){
|
|
|
+ uplink = require('./protocol/' + protocol);
|
|
|
+ me = new IRCserver;
|
|
|
+ me.introduce('serwisy.pirc.pl', '11K', 'Serwisy', 0, null);
|
|
|
+ servers.push(me);
|
|
|
+ uplink.setHandlers({
|
|
|
+ send: ircSendData,
|
|
|
+ findServer: findServer,
|
|
|
+ findUser: findUser,
|
|
|
+ killUser: killUser,
|
|
|
+ newServer: newServer,
|
|
|
+ newUser: newUser,
|
|
|
+ parseUmodes: parseUmodes,
|
|
|
+ getChannel: getChannel
|
|
|
+ });
|
|
|
+ uplink.setSettings({
|
|
|
+ ID: me.sid,
|
|
|
+ password: 'myservicespassword',
|
|
|
+ name: me.name,
|
|
|
+ description: me.description,
|
|
|
+ version: 'k4be-services',
|
|
|
+ me: me
|
|
|
+ });
|
|
|
+ connection = new net.Socket();
|
|
|
+ connection.connect(port, host, uplink.connected.bind(this));
|
|
|
+ connection.on('data', ircDataReceived);
|
|
|
+ connection.on('close', ircConnectionClosed);
|
|
|
+}
|
|
|
+
|
|
|
+function ircSendData(tags, from, cmd, args){
|
|
|
+ var data = makeTagsString(tags);
|
|
|
+ if(from){
|
|
|
+ data += ':' + from + ' ';
|
|
|
+ }
|
|
|
+ data += cmd;
|
|
|
+ if(args) for(var i=0; i<args.length; i++){
|
|
|
+ var arg = args[i];
|
|
|
+ if(arg.indexOf(' ') >= 0){ // valid for last arg only
|
|
|
+ arg = ':' + arg;
|
|
|
+ }
|
|
|
+ data += ' ' + arg;
|
|
|
+ }
|
|
|
+ console.log('<<< '+data);
|
|
|
+ data += "\r\n";
|
|
|
+ connection.write(data);
|
|
|
+}
|
|
|
+
|
|
|
+function ircDataReceived(data){
|
|
|
+ data = data.toString('utf8');
|
|
|
+ recvData += data;
|
|
|
+ var buffer = '';
|
|
|
+ for(var i=0; i<recvData.length; i++){
|
|
|
+ var c = recvData.charAt(i);
|
|
|
+ switch(c){
|
|
|
+ default: buffer += c; break;
|
|
|
+ case '\r': case '\n':
|
|
|
+ if(buffer.length > 0)
|
|
|
+ ircMessage(buffer);
|
|
|
+ buffer = '';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ recvData = buffer;
|
|
|
+}
|
|
|
+
|
|
|
+function makeTagsString(tags){
|
|
|
+ return '';
|
|
|
+}
|
|
|
+
|
|
|
+function ircMessage(data){
|
|
|
+ var msg = irc.parseLine(data);
|
|
|
+ uplink.processMessage(msg);
|
|
|
+}
|
|
|
+
|
|
|
+function ircConnectionClosed(e){
|
|
|
+ console.log('Closed: '+e);
|
|
|
+ process.exit(1);
|
|
|
+}
|
|
|
+
|
|
|
+function processReplyTags(inputTags, newTags){
|
|
|
+ return newTags;
|
|
|
+ // TODO
|
|
|
+}
|
|
|
+
|
|
|
+var irc = {
|
|
|
+ 'messagedata': function() {
|
|
|
+ this.text = '';
|
|
|
+ this.args = [];
|
|
|
+ this.tags = [];
|
|
|
+ this.command = '';
|
|
|
+ this.sender = {
|
|
|
+ 'nick': '',
|
|
|
+ 'ident': '',
|
|
|
+ 'host': '',
|
|
|
+ 'server': false,
|
|
|
+ 'user': false
|
|
|
+ };
|
|
|
+ this.time = new Date();
|
|
|
+ this.reply = function(tags, cmd, args){
|
|
|
+ var outTags = processReplyTags(this.tags, tags);
|
|
|
+ ircSendData(outTags, this.sender.nick, cmd, args);
|
|
|
+ }
|
|
|
+ this.originalString = '';
|
|
|
+ },
|
|
|
+ 'parseTags': function(tagsLine){
|
|
|
+ var tags = [];
|
|
|
+ var tagState = 'keyName';
|
|
|
+ var keyValue;
|
|
|
+ var keyName = '';
|
|
|
+ for(var i = 0; i < tagsLine.length; i++){
|
|
|
+ var cchar = tagsLine.charAt(i);
|
|
|
+ switch(tagState){
|
|
|
+ case 'keyName':
|
|
|
+ switch(cchar){
|
|
|
+ case '=':
|
|
|
+ tagState = 'keyValue';
|
|
|
+ keyValue = '';
|
|
|
+ break;
|
|
|
+ case ';':
|
|
|
+ tags[keyName] = '';
|
|
|
+ keyName = ''; // staying in tagStateKeyName
|
|
|
+ break;
|
|
|
+ default: keyName += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'keyValue':
|
|
|
+ switch(cchar){
|
|
|
+ case '\\': tagState = 'keyValueEscape'; break;
|
|
|
+ case ';':
|
|
|
+ tags[keyName] = keyValue;
|
|
|
+ keyName = '';
|
|
|
+ tagState = 'keyName';
|
|
|
+ break;
|
|
|
+ default: keyValue += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'keyValueEscape':
|
|
|
+ switch(cchar){
|
|
|
+ case ':': keyValue += ';'; break;
|
|
|
+ case 's': keyValue += ' '; break;
|
|
|
+ case 'r': keyValue += '\r'; break;
|
|
|
+ case 'n': keyValue += '\n'; break;
|
|
|
+ default: keyValue += cchar; break;
|
|
|
+ }
|
|
|
+ tagState = 'keyValue';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(keyName.length > 0) tags[keyName] = keyValue; // flush last tag
|
|
|
+ return tags;
|
|
|
+ },
|
|
|
+ 'parseLine': function(line){
|
|
|
+ var ircmsg = new irc.messagedata();
|
|
|
+
|
|
|
+ var line = line.trim();
|
|
|
+ line.replace(/^\s+|\s+$/gm,'');
|
|
|
+
|
|
|
+ if(line == ''){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ircmsg.originalString = line;
|
|
|
+
|
|
|
+ var msglen = line.length;
|
|
|
+
|
|
|
+ var pstate = 'start';
|
|
|
+ var currArg = '';
|
|
|
+ var tags = '';
|
|
|
+ var haveText = false;
|
|
|
+
|
|
|
+ console.log('>>> ' + line);
|
|
|
+
|
|
|
+ for(var i = 0; i < msglen; i++){
|
|
|
+ var cchar = line.charAt(i);
|
|
|
+ switch(pstate){
|
|
|
+ case 'start':
|
|
|
+ switch(cchar){
|
|
|
+ case '@': pstate = 'tags'; break;
|
|
|
+ case ':': pstate = 'senderNick'; break;
|
|
|
+ default:
|
|
|
+ pstate = 'command';
|
|
|
+ ircmsg.command += cchar;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'tags':
|
|
|
+ switch(cchar){
|
|
|
+ case ' ':
|
|
|
+ pstate = 'start';
|
|
|
+ ircmsg.tags = irc.parseTags(tags);
|
|
|
+ break;
|
|
|
+ default: tags += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'senderNick':
|
|
|
+ switch(cchar){
|
|
|
+ case '!': pstate = 'senderUser'; break;
|
|
|
+ case '@': pstate = 'senderHost'; break;
|
|
|
+ case ' ': pstate = 'command'; break;
|
|
|
+ default: ircmsg.sender.nick += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'senderUser':
|
|
|
+ switch(cchar){
|
|
|
+ case '@': pstate = 'senderHost'; break;
|
|
|
+ case ' ': pstate = 'command'; break;
|
|
|
+ default: ircmsg.sender.ident += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'senderHost':
|
|
|
+ switch(cchar){
|
|
|
+ case ' ': pstate = 'command'; break;
|
|
|
+ default: ircmsg.sender.host += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'command':
|
|
|
+ switch(cchar){
|
|
|
+ case ' ': pstate = 'args'; break;
|
|
|
+ default: ircmsg.command += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'args':
|
|
|
+ switch(cchar){
|
|
|
+ case ' ':
|
|
|
+ if(currArg != ''){
|
|
|
+ ircmsg.args.push(currArg);
|
|
|
+ }
|
|
|
+ currArg = '';
|
|
|
+ break;
|
|
|
+ case ':':
|
|
|
+ if(prevChar == ' '){
|
|
|
+ pstate = 'message';
|
|
|
+ haveText = true;
|
|
|
+ } else {
|
|
|
+ currArg += cchar;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default: currArg += cchar; break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'message':
|
|
|
+ ircmsg.text += cchar;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ var prevChar = cchar;
|
|
|
+ }
|
|
|
+ if(pstate == 'args'){
|
|
|
+ ircmsg.args.push(currArg);
|
|
|
+ }
|
|
|
+
|
|
|
+ ircmsg.sender = uplink.processSender(ircmsg.sender);
|
|
|
+ if(!ircmsg.sender){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!ircmsg.sender.server && !ircmsg.sender.user){
|
|
|
+ if(ircmsg.sender.ident == '' && ircmsg.sender.host == '' && ircmsg.sender.nick.indexOf('.')!=-1){
|
|
|
+ ircmsg.sender.server = true;
|
|
|
+ } else {
|
|
|
+ ircmsg.sender.user = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!haveText){
|
|
|
+ ircmsg.text = ircmsg.args[ircmsg.args.length-1]; // handling last argument as text if : is missing
|
|
|
+ } else {
|
|
|
+ ircmsg.args.push(ircmsg.text); // handling text as a last argument as required by the protocol
|
|
|
+ }
|
|
|
+
|
|
|
+// add u@h
|
|
|
+/* if(ircmsg.sender.user){
|
|
|
+ if(ircmsg.sender.ident) users.getUser(ircmsg.sender.nick).setIdent(ircmsg.sender.ident);
|
|
|
+ if(ircmsg.sender.host) users.getUser(ircmsg.sender.nick).setHost(ircmsg.sender.host);
|
|
|
+ }*/
|
|
|
+
|
|
|
+// process known tags
|
|
|
+/* if('time' in ircmsg.tags){
|
|
|
+ ircmsg.time = parseISOString(ircmsg.tags['time']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if('account' in ircmsg.tags){
|
|
|
+ users.getUser(ircmsg.sender.nick).setAccount(ircmsg.tags['account']);
|
|
|
+ }*/
|
|
|
+
|
|
|
+// console.log(ircmsg);
|
|
|
+
|
|
|
+ return ircmsg;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|