Fix some minor issues
[KiwiIRC.git] / server / irc / connection.js
CommitLineData
2a8e95d1
D
1var net = require('net'),
2 tls = require('tls'),
3 events = require('events'),
15fefff7 4 util = require('util'),
795014b1 5 _ = require('underscore');
2a8e95d1 6
15fefff7 7var IrcConnection = function (hostname, port, ssl, nick, user, pass) {
2a8e95d1
D
8 var that = this;
9 events.EventEmitter.call(this);
10
11 if (ssl) {
36108ca9
D
12 this.socket = tls.connect({
13 host: hostname,
14 port: port,
15 rejectUnauthorized: global.config.reject_unauthorised_certificates
16 }, function () {
17 connect_handler.apply(that, arguments);
18 });
2a8e95d1
D
19 } else {
20 this.socket = net.createConnection(port, hostname);
21 this.socket.on('connect', function () {
22 connect_handler.apply(that, arguments);
23 });
24 }
25
d2d91c10
D
26 this.socket.on('error', function (event) {
27 that.emit('error', event);
2a8e95d1
D
28 });
29
30 this.socket.setEncoding('utf-8');
31
32 this.socket.on('data', function () {
33 parse.apply(that, arguments);
34 });
35
36 this.socket.on('close', function () {
37 that.emit('close');
38 });
39
40 this.connected = false;
41 this.registered = false;
eec8c71e 42 this.cap_negotiation = true;
2a8e95d1
D
43 this.nick = nick;
44 this.user = user;
15fefff7 45 this.irc_host = {hostname: hostname, port: port};
2a8e95d1
D
46 this.ssl = !(!ssl);
47 this.options = Object.create(null);
eec8c71e 48 this.cap = {requested: [], enabled: []};
7dfe47c6 49 this.sasl = false;
2a8e95d1 50
2a8e95d1
D
51 this.password = pass;
52 this.hold_last = false;
53 this.held_data = '';
54};
55util.inherits(IrcConnection, events.EventEmitter);
56
57module.exports.IrcConnection = IrcConnection;
58
59
60IrcConnection.prototype.write = function (data, callback) {
61 write.call(this, data + '\r\n', 'utf-8', callback);
62};
63
64IrcConnection.prototype.end = function (data, callback) {
2a8e95d1
D
65 end.call(this, data + '\r\n', 'utf-8', callback);
66};
67
c08717da
D
68IrcConnection.prototype.dispose = function () {
69 this.removeAllListeners();
70};
71
72
2a8e95d1
D
73var write = function (data, encoding, callback) {
74 this.socket.write(data, encoding, callback);
75};
76
77var end = function (data, encoding, callback) {
78 this.socket.end(data, encoding, callback);
79};
80
81
82var connect_handler = function () {
15fefff7
D
83 var that = this,
84 connect_data;
85
86 // Build up data to be used for webirc/etc detection
87 connect_data = {
88 user: this.user,
89 nick: this.nick,
90 realname: '[www.kiwiirc.com] ' + this.nick,
91 username: this.nick.replace(/[^0-9a-zA-Z\-_.]/, ''),
92 irc_host: this.irc_host
93 };
94
95 // Let the webirc/etc detection modify any required parameters
96 connect_data = findWebIrc(connect_data);
97
98 // Send any initial data for webirc/etc
99 if (connect_data.prepend_data) {
100 _.each(connect_data.prepend_data, function(data) {
101 that.write(data);
102 });
2a8e95d1 103 }
15fefff7 104
eec8c71e 105 this.write('CAP LS');
7dfe47c6
JA
106
107 this.registration_timeout = setTimeout(function () {
3dd5ff0a 108 that.register();
7dfe47c6 109 }, 1000);
2a8e95d1
D
110
111 this.connected = true;
2a8e95d1
D
112 this.emit('connected');
113};
114
7dfe47c6
JA
115IrcConnection.prototype.register = function () {
116 if (this.registration_timeout !== null) {
117 clearTimeout(this.registeration_timeout);
118 this.registration_timeout = null;
119 }
285bffb5 120 if ((this.password) && (!this.sasl)) {
7dfe47c6
JA
121 this.write('PASS ' + this.password);
122 }
123 this.write('NICK ' + this.nick);
124 this.write('USER ' + this.nick.replace(/[^0-9a-zA-Z\-_.]/, '') + ' 0 0 :' + '[www.kiwiirc.com] ' + this.nick);
125 if (this.cap_negotation) {
126 this.write('CAP END');
127 }
128};
2a8e95d1 129
15fefff7
D
130
131
132function findWebIrc(connect_data) {
b737610b
JA
133 var webirc_pass = global.config.webirc_pass;
134 var ip_as_username = global.config.ip_as_username;
15fefff7
D
135 var tmp;
136
137 // Do we have a WEBIRC password for this?
138 if (webirc_pass && webirc_pass[connect_data.irc_host.hostname]) {
139 tmp = 'WEBIRC ' + webirc_pass[connect_data.irc_host.hostname] + ' KiwiIRC ';
140 tmp += connect_data.user.hostname + ' ' + connect_data.user.address;
141 connect_data.prepend_data = [tmp];
142 }
143
144
145 // Check if we need to pass the users IP as its username/ident
146 if (ip_as_username && ip_as_username.indexOf(connect_data.irc_host.hostname) > -1) {
147 // Get a hex value of the clients IP
148 connect_data.username = connect_data.user.address.split('.').map(function(i, idx){
149 return parseInt(i, 10).toString(16);
150 }).join('');
151
152 }
153
154 return connect_data;
155}
156
157
158
16e717f5 159parse_regex = /^(?:(?:(?:(@[^ ]+) )?):(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@?([a-z0-9\.\-:\/]+)?) )?(\S+)(?: (?!:)(.+?))?(?: :(.+))?$/i;
2a8e95d1
D
160var parse = function (data) {
161 var i,
162 msg,
16e717f5
JA
163 msg2,
164 trm,
165 j,
166 tags = [],
167 tag;
2a8e95d1
D
168
169 if ((this.hold_last) && (this.held_data !== '')) {
170 data = this.held_data + data;
171 this.hold_last = false;
172 this.held_data = '';
173 }
174 if (data.substr(-1) !== '\n') {
175 this.hold_last = true;
176 }
177 data = data.split("\n");
178 for (i = 0; i < data.length; i++) {
179 if (data[i]) {
180 if ((this.hold_last) && (i === data.length - 1)) {
181 this.held_data = data[i];
182 break;
183 }
184
185 // We have a complete line of data, parse it!
186 msg = parse_regex.exec(data[i].replace(/^\r+|\r+$/, ''));
187 if (msg) {
16e717f5
JA
188 if (msg[1]) {
189 tags = msg[1].split(';');
190 for (j = 0; j < tags.length; j++) {
191 tag = tags[j].split('=');
192 tags[j] = {tag: tag[0], value: tag[1]};
193 }
194 }
2a8e95d1 195 msg = {
16e717f5
JA
196 tags: tags,
197 prefix: msg[2],
198 nick: msg[3],
199 ident: msg[4],
200 hostname: msg[5] || '',
201 command: msg[6],
202 params: msg[7] || '',
203 trailing: (msg[8]) ? msg[8].trim() : ''
2a8e95d1
D
204 };
205 msg.params = msg.params.split(' ');
206
207 this.emit('irc_' + msg.command.toUpperCase(), msg);
208 } else {
209 console.log("Malformed IRC line: " + data[i].replace(/^\r+|\r+$/, ''));
210 }
211 }
212 }
213};