16 this.init = function (objs
) {
29 starttls
= objs
.starttls
;
30 kiwi
= require('./kiwi.js');
39 * Some process changes
41 this.setTitle = function () {
42 process
.title
= 'kiwiirc';
45 this.changeUser = function () {
46 if (typeof kiwi
.config
.group
!== 'undefined' && kiwi
.config
.group
!== '') {
48 process
.setgid(kiwi
.config
.group
);
50 console
.log('Failed to set gid: ' + err
);
55 if (typeof kiwi
.config
.user
!== 'undefined' && kiwi
.config
.user
!== '') {
57 process
.setuid(kiwi
.config
.user
);
59 console
.log('Failed to set uid: ' + e
);
77 RPL_WHOISSERVER
: '312',
78 RPL_WHOISOPERATOR
: '313',
80 RPL_ENDOFWHOIS
: '318',
81 RPL_WHOISCHANNELS
: '319',
85 RPL_ENDOFNAMES
: '366',
87 RPL_WHOISMODES
: '379',
88 ERR_NOSUCHNICK
: '401',
89 ERR_CANNOTSENDTOCHAN
: '404',
90 ERR_TOOMANYCHANNELS
: '405',
91 ERR_NICKNAMEINUSE
: '433',
92 ERR_USERNOTINCHANNEL
: '441',
93 ERR_NOTONCHANNEL
: '442',
94 ERR_NOTREGISTERED
: '451',
95 ERR_LINKCHANNEL
: '470',
96 ERR_CHANNELISFULL
: '471',
97 ERR_INVITEONLYCHAN
: '473',
98 ERR_BANNEDFROMCHAN
: '474',
99 ERR_BADCHANNELKEY
: '475',
100 ERR_CHANOPRIVSNEEDED
: '482',
106 this.parseIRCMessage = function (websocket
, ircSocket
, data
) {
107 /*global ircSocketDataHandler */
108 var msg
, regex
, opts
, options
, opt
, i
, j
, matches
, nick
, users
, chan
, channel
, params
, prefix
, prefixes
, nicklist
, caps
, rtn
, obj
;
109 regex
= /^(?::(?:([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)|([a-z0-9\x5B-\x60\x7B-\x7D\.\-]+)!([a-z0-9~\.\-_|]+)@?([a-z0-9\.\-:]+)?) )?([a-z0-9]+)(?:(?: ([^:]+))?(?: :(.+))?)$/i;
110 msg
= regex
.exec(data
);
116 hostname
: msg
[4] || '',
118 params
: msg
[6] || '',
119 trailing
: (msg
[7]) ? msg
[7].trim() : ''
121 switch (msg
.command
.toUpperCase()) {
123 websocket
.sendServerLine('PONG ' + msg
.trailing
);
125 case ircNumerics
.RPL_WELCOME
:
126 if (ircSocket
.IRC
.CAP
.negotiating
) {
127 ircSocket
.IRC
.CAP
.negotiating
= false;
128 ircSocket
.IRC
.CAP
.enabled
= [];
129 ircSocket
.IRC
.CAP
.requested
= [];
130 ircSocket
.IRC
.registered
= true;
132 websocket
.sendClientEvent('connect', {connected
: true, host
: null});
134 case ircNumerics
.RPL_ISUPPORT
:
135 opts
= msg
.params
.split(" ");
137 for (i
= 0; i
< opts
.length
; i
++) {
138 opt
= opts
[i
].split("=", 2);
139 opt
[0] = opt
[0].toUpperCase();
140 ircSocket
.IRC
.options
[opt
[0]] = opt
[1] || true;
141 if (_
.include(['NETWORK', 'PREFIX', 'CHANTYPES'], opt
[0])) {
142 if (opt
[0] === 'PREFIX') {
143 regex
= /\(([^)]*)\)(.*)/;
144 matches
= regex
.exec(opt
[1]);
145 if ((matches
) && (matches
.length
=== 3)) {
146 ircSocket
.IRC
.options
[opt
[0]] = [];
147 for (j
= 0; j
< matches
[2].length
; j
++) {
148 //ircSocket.IRC.options[opt[0]][matches[2].charAt(j)] = matches[1].charAt(j);
149 ircSocket
.IRC
.options
[opt
[0]].push({symbol
: matches
[2].charAt(j
), mode
: matches
[1].charAt(j
)});
150 //console.log({symbol: matches[2].charAt(j), mode: matches[1].charAt(j)});
152 //console.log(ircSocket.IRC.options);
157 websocket
.sendClientEvent('options', {server
: '', "options": ircSocket
.IRC
.options
});
159 case ircNumerics
.RPL_WHOISUSER
:
160 case ircNumerics
.RPL_WHOISSERVER
:
161 case ircNumerics
.RPL_WHOISOPERATOR
:
162 case ircNumerics
.RPL_ENDOFWHOIS
:
163 case ircNumerics
.RPL_WHOISCHANNELS
:
164 case ircNumerics
.RPL_WHOISMODES
:
165 websocket
.sendClientEvent('whois', {server
: '', nick
: msg
.params
.split(" ", 3)[1], "msg": msg
.trailing
});
167 case ircNumerics
.RPL_WHOISIDLE
:
168 params
= msg
.params
.split(" ", 4);
169 rtn
= {server
: '', nick
: params
[1], idle
: params
[2]};
171 rtn
.logon
= params
[3];
173 websocket
.sendClientEvent('whois', rtn
);
175 case ircNumerics
.RPL_MOTD
:
176 websocket
.sendClientEvent('motd', {server
: '', "msg": msg
.trailing
});
178 case ircNumerics
.RPL_NAMEREPLY
:
179 params
= msg
.params
.split(" ");
182 users
= msg
.trailing
.split(" ");
183 prefixes
= _
.values(ircSocket
.IRC
.options
.PREFIX
);
186 _
.each(users
, function (user
) {
187 if (_
.include(prefix
, user
.charAt(0))) {
188 prefix
= user
.charAt(0);
189 user
= user
.substring(1);
190 nicklist
[user
] = prefix
;
195 websocket
.sendClientEvent('userlist', {server
: '', 'users': nicklist
, channel
: chan
});
201 websocket
.sendClientEvent('userlist', {server
: '', "users": nicklist
, channel
: chan
});
206 case ircNumerics
.RPL_ENDOFNAMES
:
207 websocket
.sendClientEvent('userlist_end', {server
: '', channel
: msg
.params
.split(" ")[1]});
209 case ircNumerics
.ERR_LINKCHANNEL
:
210 params
= msg
.params
.split(" ");
211 websocket
.sendClientEvent('channel_redirect', {from: params
[1], to
: params
[2]});
213 case ircNumerics
.ERR_NOSUCHNICK
:
214 websocket
.sendClientEvent('irc_error', {error
: 'no_such_nick', nick
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
217 // Some BNC's send malformed JOIN causing the channel to be as a
218 // parameter instead of trailing.
219 if (typeof msg
.trailing
=== 'string' && msg
.trailing
!== '') {
220 channel
= msg
.trailing
;
221 } else if (typeof msg
.params
=== 'string' && msg
.params
!== '') {
222 channel
= msg
.params
;
225 websocket
.sendClientEvent('join', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: channel
});
226 if (msg
.nick
=== ircSocket
.IRC
.nick
) {
227 websocket
.sendServerLine('NAMES ' + msg
.trailing
);
231 websocket
.sendClientEvent('part', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), message
: msg
.trailing
});
234 params
= msg
.params
.split(" ");
235 websocket
.sendClientEvent('kick', {kicked
: params
[1], nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: params
[0].trim(), message
: msg
.trailing
});
238 websocket
.sendClientEvent('quit', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, message
: msg
.trailing
});
241 if ((msg
.trailing
.charAt(0) === String
.fromCharCode(1)) && (msg
.trailing
.charAt(msg
.trailing
.length
- 1) === String
.fromCharCode(1))) {
242 // It's a CTCP response
243 websocket
.sendClientEvent('ctcp_response', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), msg
: msg
.trailing
.substr(1, msg
.trailing
.length
- 2)});
245 websocket
.sendClientEvent('notice', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), msg
: msg
.trailing
});
249 websocket
.sendClientEvent('nick', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, newnick
: msg
.trailing
});
252 obj
= {nick
: msg
.nick
, channel
: msg
.params
, topic
: msg
.trailing
};
253 websocket
.sendClientEvent('topic', obj
);
255 case ircNumerics
.RPL_TOPIC
:
256 obj
= {nick
: '', channel
: msg
.params
.split(" ")[1], topic
: msg
.trailing
};
257 websocket
.sendClientEvent('topic', obj
);
259 case ircNumerics
.RPL_NOTOPIC
:
260 obj
= {nick
: '', channel
: msg
.params
.split(" ")[1], topic
: ''};
261 websocket
.sendClientEvent('topic', obj
);
264 opts
= msg
.params
.split(" ");
265 params
= {nick
: msg
.nick
};
266 switch (opts
.length
) {
268 params
.effected_nick
= opts
[0];
269 params
.mode
= msg
.trailing
;
272 params
.channel
= opts
[0];
273 params
.mode
= opts
[1];
276 params
.channel
= opts
[0];
277 params
.mode
= opts
[1];
278 params
.effected_nick
= opts
[2];
281 websocket
.sendClientEvent('mode', params
);
284 if ((msg
.trailing
.charAt(0) === String
.fromCharCode(1)) && (msg
.trailing
.charAt(msg
.trailing
.length
- 1) === String
.fromCharCode(1))) {
285 // It's a CTCP request
286 if (msg
.trailing
.substr(1, 6) === 'ACTION') {
287 websocket
.sendClientEvent('action', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), msg
: msg
.trailing
.substr(7, msg
.trailing
.length
- 2)});
288 } else if (msg
.trailing
.substr(1, 7) === 'VERSION') {
289 ircSocket
.write('NOTICE ' + msg
.nick
+ ' :' + String
.fromCharCode(1) + 'VERSION KiwiIRC' + String
.fromCharCode(1) + '\r\n');
291 websocket
.sendClientEvent('ctcp_request', {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), msg
: msg
.trailing
.substr(1, msg
.trailing
.length
- 2)});
294 obj
= {nick
: msg
.nick
, ident
: msg
.ident
, hostname
: msg
.hostname
, channel
: msg
.params
.trim(), msg
: msg
.trailing
};
295 websocket
.sendClientEvent('msg', obj
);
299 caps
= kiwi
.config
.cap_options
;
300 options
= msg
.trailing
.split(" ");
301 switch (_
.last(msg
.params
.split(" "))) {
304 _
.each(_
.intersect(caps
, options
), function (cap
) {
309 ircSocket
.IRC
.CAP
.requested
.push(cap
);
311 if (opts
.length
> 0) {
312 websocket
.sendServerLine('CAP REQ :' + opts
);
314 websocket
.sendServerLine('CAP END');
317 /*if (_.include(options, 'tls')) {
318 websocket.sendServerLine('STARTTLS');
319 ircSocket.IRC.CAP.requested.push('tls');
323 _
.each(options
, function (cap
) {
324 ircSocket
.IRC
.CAP
.enabled
.push(cap
);
326 if (_
.last(msg
.params
.split(" ")) !== '*') {
327 ircSocket
.IRC
.CAP
.requested
= [];
328 ircSocket
.IRC
.CAP
.negotiating
= false;
329 websocket
.sendServerLine('CAP END');
333 ircSocket
.IRC
.CAP
.requested
= [];
334 ircSocket
.IRC
.CAP
.negotiating
= false;
335 websocket
.sendServerLine('CAP END');
339 /*case ircNumerics.RPL_STARTTLS:
342 listeners = ircSocket.listeners('data');
343 ircSocket.removeAllListeners('data');
344 ssl_socket = starttls(ircSocket, {}, function () {
345 ssl_socket.on("data", function (data) {
346 ircSocketDataHandler(data, websocket, ssl_socket);
348 ircSocket = ssl_socket;
350 _.each(listeners, function (listener) {
351 ircSocket.addListener('data', listener);
354 //console.log(ircSocket);
359 case ircNumerics
.ERR_CANNOTSENDTOCHAN
:
360 websocket
.sendClientEvent('irc_error', {error
: 'cannot_send_to_chan', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
362 case ircNumerics
.ERR_TOOMANYCHANNELS
:
363 websocket
.sendClientEvent('irc_error', {error
: 'too_many_channels', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
365 case ircNumerics
.ERR_USERNOTINCHANNEL
:
366 params
= msg
.params
.split(" ");
367 websocket
.sendClientEvent('irc_error', {error
: 'user_not_in_channel', nick
: params
[0], channel
: params
[1], reason
: msg
.trainling
});
369 case ircNumerics
.ERR_NOTONCHANNEL
:
370 websocket
.sendClientEvent('irc_error', {error
: 'not_on_channel', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
372 case ircNumerics
.ERR_CHANNELISFULL
:
373 websocket
.sendClientEvent('irc_error', {error
: 'channel_is_full', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
375 case ircNumerics
.ERR_INVITEONLYCHAN
:
376 websocket
.sendClientEvent('irc_error', {error
: 'invite_only_channel', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
378 case ircNumerics
.ERR_BANNEDFROMCHAN
:
379 websocket
.sendClientEvent('irc_error', {error
: 'banned_from_channel', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
381 case ircNumerics
.ERR_BADCHANNELKEY
:
382 websocket
.sendClientEvent('irc_error', {error
: 'bad_channel_key', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
384 case ircNumerics
.ERR_CHANOPRIVSNEEDED
:
385 websocket
.sendClientEvent('irc_error', {error
: 'chanop_privs_needed', channel
: msg
.params
.split(" ")[1], reason
: msg
.trailing
});
387 case ircNumerics
.ERR_NICKNAMEINUSE
:
388 websocket
.sendClientEvent('irc_error', {error
: 'nickname_in_use', nick
: _
.last(msg
.params
.split(" ")), reason
: msg
.trailing
});
392 websocket
.sendClientEvent('irc_error', {error
: 'error', reason
: msg
.trailing
});
393 websocket
.disconnect();
395 case ircNumerics
.ERR_NOTREGISTERED
:
396 if (ircSocket
.IRC
.registered
) {
397 console
.log('Kiwi thinks user is registered, but the IRC server thinks differently');
401 console
.log("Unknown command (" + String(msg
.command
).toUpperCase() + ")");
404 console
.log("Malformed IRC line");
414 * NOTE: Some IRC servers or BNC's out there incorrectly use
415 * only \n as a line splitter.
417 this.ircSocketDataHandler = function (data
, websocket
, ircSocket
) {
419 if ((ircSocket
.holdLast
) && (ircSocket
.held
!== '')) {
420 data
= ircSocket
.held
+ data
;
421 ircSocket
.holdLast
= false;
424 if (data
.substr(-1) !== '\n') {
425 ircSocket
.holdLast
= true;
427 data
= data
.split("\n");
428 for (i
= 0; i
< data
.length
; i
++) {
430 if ((ircSocket
.holdLast
) && (i
=== data
.length
- 1)) {
431 ircSocket
.held
= data
[i
];
435 // We have a complete line of data, parse it!
436 kiwi
.parseIRCMessage(websocket
, ircSocket
, data
[i
].replace(/^\r+|\r+$/, ''));
445 this.httpHandler = function (request
, response
) {
446 var uri
, subs
, useragent
, agent
, server_set
, server
, nick
, debug
, touchscreen
, hash
,
447 min
= {}, public_http_path
;
448 if (kiwi
.config
.handle_http
) {
449 uri
= url
.parse(request
.url
, true);
450 subs
= uri
.pathname
.substr(0, 4);
451 if (uri
.pathname
=== '/js/all.js') {
452 if (kiwi
.cache
.alljs
=== '') {
453 public_http_path
= kiwi
.kiwi_root
+ '/' + kiwi
.config
.public_http
;
455 min
.util
= fs
.readFileSync(public_http_path
+ 'js/util.js');
456 min
.gateway
= fs
.readFileSync(public_http_path
+ 'js/gateway.js');
457 min
.front
= fs
.readFileSync(public_http_path
+ 'js/front.js');
458 min
.iscroll
= fs
.readFileSync(public_http_path
+ 'js/iscroll.js');
459 min
.ast
= jsp
.parse(min
.util
+ min
.gateway
+ min
.front
+ min
.iscroll
);
460 min
.ast
= pro
.ast_mangle(min
.ast
);
461 min
.ast
= pro
.ast_squeeze(min
.ast
);
462 min
.final_code
= pro
.gen_code(min
.ast
);
463 kiwi
.cache
.alljs
= min
.final_code
;
464 hash
= crypto
.createHash('md5').update(kiwi
.cache
.alljs
);
465 kiwi
.cache
.alljs_hash
= hash
.digest('base64');
467 if (request
.headers
['if-none-match'] === kiwi
.cache
.alljs_hash
) {
468 response
.statusCode
= 304;
470 response
.setHeader('ETag', kiwi
.cache
.alljs_hash
);
471 response
.write(kiwi
.cache
.alljs
);
474 } else if ((subs
=== '/js/') || (subs
=== '/css') || (subs
=== '/img')) {
475 request
.addListener('end', function () {
476 kiwi
.fileServer
.serve(request
, response
);
478 } else if (uri
.pathname
=== '/') {
479 useragent
= (response
.headers
) ? response
.headers
['user-agent'] : '';
480 if (useragent
.indexOf('android') !== -1) {
483 } else if (useragent
.indexOf('iphone') !== -1) {
486 } else if (useragent
.indexOf('ipad') !== -1) {
489 } else if (useragent
.indexOf('ipod') !== -1) {
498 server_set
= ((typeof uri
.query
.server
!== 'undefined') && (uri
.query
.server
!== ''));
499 server
= uri
.query
.server
|| 'irc.anonnet.org';
500 nick
= uri
.query
.nick
|| '';
501 debug
= (uri
.query
.debug
!== '');
504 server
= 'irc.anonnet.org';
507 response
.setHeader('X-Generated-By', 'KiwiIRC');
508 hash
= crypto
.createHash('md5').update(touchscreen
? 't' : 'f').update(debug
? 't' : 'f').update(server_set
? 't' : 'f').update(server
).update(nick
).update(agent
).update(JSON
.stringify(kiwi
.config
)).digest('base64');
509 if (kiwi
.cache
.html
[hash
]) {
510 if (request
.headers
['if-none-match'] === kiwi
.cache
.html
[hash
].hash
) {
511 response
.statusCode
= 304;
513 response
.setHeader('Etag', kiwi
.cache
.html
[hash
].hash
);
514 response
.write(kiwi
.cache
.html
[hash
].html
);
518 kiwi
.jade
.renderFile(__dirname
+ '/client/index.html.jade', { locals
: { "touchscreen": touchscreen
, "debug": debug
, "server_set": server_set
, "server": server
, "nick": nick
, "agent": agent
, "config": kiwi
.config
}}, function (err
, html
) {
520 var hash2
= crypto
.createHash('md5').update(html
).digest('base64');
521 kiwi
.cache
.html
[hash
] = {"html": html
, "hash": hash2
};
522 if (request
.headers
['if-none-match'] === hash2
) {
523 response
.statusCode
= 304;
525 response
.setHeader('Etag', hash2
);
526 response
.write(html
);
529 response
.statusCode
= 500;
534 } else if (uri
.pathname
.substr(0, 10) === '/socket.io') {
537 response
.statusCode
= 404;
546 this.websocketListen = function (port
, host
, handler
, secure
, key
, cert
) {
547 if (kiwi
.httpServer
) {
548 kiwi
.httpServer
.close();
551 kiwi
.httpServer
= https
.createServer({key
: fs
.readFileSync(__dirname
+ '/' + key
), cert
: fs
.readFileSync(__dirname
+ '/' + cert
)}, handler
);
552 kiwi
.io
= ws
.listen(kiwi
.httpServer
, {secure
: true});
553 kiwi
.httpServer
.listen(port
, host
);
555 kiwi
.httpServer
= http
.createServer(handler
);
556 kiwi
.io
= ws
.listen(kiwi
.httpServer
, {secure
: false});
557 kiwi
.httpServer
.listen(port
, host
);
560 kiwi
.io
.set('log level', 1);
561 kiwi
.io
.enable('browser client minification');
562 kiwi
.io
.enable('browser client etag');
563 kiwi
.io
.set('transports', kiwi
.config
.transports
);
565 kiwi
.io
.of('/kiwi').authorization(function (handshakeData
, callback
) {
566 var address
= handshakeData
.address
.address
;
568 if (typeof kiwi
.connections
[address
] === 'undefined') {
569 kiwi
.connections
[address
] = {count
: 0, sockets
: []};
571 callback(null, true);
572 }).on('connection', kiwi
.websocketConnection
);
580 this.websocketConnection = function (websocket
) {
582 websocket
.kiwi
= {address
: websocket
.handshake
.address
.address
};
583 con
= kiwi
.connections
[websocket
.kiwi
.address
];
585 if (con
.count
>= kiwi
.config
.max_client_conns
) {
586 websocket
.emit('too_many_connections');
587 websocket
.disconnect();
590 con
.sockets
.push(websocket
);
592 websocket
.sendClientEvent = function (event_name
, data
) {
593 kiwi
.kiwi_mod
.run(event_name
, data
, {websocket
: this});
594 data
.event
= event_name
;
595 websocket
.emit('message', data
);
598 websocket
.sendServerLine = function (data
, eol
) {
599 eol
= (typeof eol
=== 'undefined') ? '\r\n' : eol
;
600 websocket
.ircSocket
.write(data
+ eol
);
603 websocket
.on('irc connect', kiwi
.websocketIRCConnect
);
604 websocket
.on('message', kiwi
.websocketMessage
);
605 websocket
.on('disconnect', kiwi
.websocketDisconnect
);
613 this.websocketIRCConnect = function (websocket
, nick
, host
, port
, ssl
, callback
) {
615 //setup IRC connection
617 ircSocket
= net
.createConnection(port
, host
);
619 ircSocket
= tls
.connect(port
, host
);
621 ircSocket
.setEncoding('ascii');
622 ircSocket
.IRC
= {options
: {}, CAP
: {negotiating
: true, requested
: [], enabled
: []}, registered
: false};
623 ircSocket
.on('error', function (e
) {
624 if (ircSocket
.IRC
.registered
) {
625 websocket
.emit('disconnect');
627 websocket
.emit('error', e
.message
);
630 websocket
.ircSocket
= ircSocket
;
631 ircSocket
.holdLast
= false;
634 ircSocket
.on('data', function (data
) {
635 kiwi
.ircSocketDataHandler(data
, websocket
, ircSocket
);
638 ircSocket
.IRC
.nick
= nick
;
639 // Send the login data
640 dns
.reverse(websocket
.kiwi
.address
, function (err
, domains
) {
641 //console.log(domains);
642 websocket
.kiwi
.hostname
= (err
) ? websocket
.kiwi
.address
: _
.first(domains
);
643 if ((kiwi
.config
.webirc
) && (kiwi
.config
.webirc_pass
[host
])) {
644 websocket
.sendServerLine('WEBIRC ' + kiwi
.config
.webirc_pass
[host
] + ' KiwiIRC ' + websocket
.kiwi
.hostname
+ ' ' + websocket
.kiwi
.address
);
646 websocket
.sendServerLine('CAP LS');
647 websocket
.sendServerLine('NICK ' + nick
);
648 websocket
.sendServerLine('USER ' + nick
.replace(/[^0-9a-zA-Z\-_.]/, '') + '_kiwi 0 0 :' + nick
);
650 if ((callback
) && (typeof (callback
) === 'function')) {
658 this.websocketMessage = function (websocket
, msg
, callback
) {
661 msg
.data
= JSON
.parse(msg
.data
);
662 args
= msg
.data
.args
;
663 switch (msg
.data
.method
) {
665 if ((args
.target
) && (args
.msg
)) {
666 obj
= kiwi
.kiwi_mod
.run('msgsend', args
, {websocket
: websocket
});
668 websocket
.sendServerLine('PRIVMSG ' + args
.target
+ ' :' + args
.msg
);
673 if ((args
.target
) && (args
.msg
)) {
674 websocket
.sendServerLine('PRIVMSG ' + args
.target
+ ' :\ 1' + String
.fromCharCode(1) + 'ACTION ' + args
.msg
+ String
.fromCharCode(1));
678 websocket
.sendServerLine(args
.data
);
682 _
.each(args
.channel
.split(","), function (chan
) {
683 websocket
.sendServerLine('JOIN ' + chan
);
689 websocket
.sendServerLine('TOPIC ' + args
.channel
+ ' :' + args
.topic
);
693 websocket
.ircSocket
.end('QUIT :' + args
.message
+ '\r\n');
694 websocket
.sentQUIT
= true;
695 websocket
.ircSocket
.destroySoon();
696 websocket
.disconnect();
699 if ((args
.target
) && (args
.msg
)) {
700 websocket
.sendServerLine('NOTICE ' + args
.target
+ ' :' + args
.msg
);
705 if ((callback
) && (typeof (callback
) === 'function')) {
709 console
.log("Caught error: " + e
);
715 this.websocketDisconnect = function (websocket
) {
718 if ((!websocket
.sentQUIT
) && (websocket
.ircSocket
)) {
720 websocket
.ircSocket
.end('QUIT :' + kiwi
.config
.quit_message
+ '\r\n');
721 websocket
.sentQUIT
= true;
722 websocket
.ircSocket
.destroySoon();
726 con
= kiwi
.connections
[websocket
.kiwi
.address
];
728 con
.sockets
= _
.reject(con
.sockets
, function (sock
) {
729 return sock
=== websocket
;
738 this.rehash = function () {
740 reload_config
= kiwi
.loadConfig();
742 // If loading the new config errored out, dont attempt any changes
743 if (reload_config
=== false) {
747 // We just want the settings that have been changed
748 changes
= reload_config
[1];
750 if (Object
.keys(changes
).length
!== 0) {
751 console
.log('%s config changes: \n', Object
.keys(changes
).length
, changes
);
759 kiwi
.websocketListen(kiwi
.config
.port
, kiwi
.config
.bind_address
, kiwi
.httpHandler
, kiwi
.config
.listen_ssl
, kiwi
.config
.ssl_key
, kiwi
.config
.ssl_cert
);
761 delete changes
.bind_address
;
762 delete changes
.listen_ssl
;
763 delete changes
.ssl_key
;
764 delete changes
.ssl_cert
;
770 delete changes
.group
;
774 kiwi
.kiwi_mod
.loadModules(kiwi_root
, kiwi
.config
);
775 kiwi
.kiwi_mod
.printMods();
776 delete changes
.module_dir
;
777 delete changes
.modules
;
783 // Also clear the kiwi.cached javascript and HTML
784 if (kiwi
.config
.handle_http
) {
785 kiwi
.cache
= {alljs
: '', html
: []};
796 * KiwiIRC controlling via STDIN
798 this.startControll = function () {
799 process
.stdin
.resume();
800 process
.stdin
.on('data', function (chunk
) {
802 command
= chunk
.toString().trim();
805 console
.log('Rehashing...');
806 console
.log(kiwi
.rehash() ? 'Rehash complete' : 'Rehash failed');
810 console
.log('Recoding...');
811 console
.log(kiwi
.recode() ? 'Recode complete' : 'Recode failed');
815 console
.log('Unknown command \'' + command
+ '\'');