BSD and expact license modified
[KiwiIRC.git] / server / clientcommands.js
1 var _ = require('lodash');
2
3
4
5
6 var ClientCommands = function (client) {
7 this.client = client;
8 };
9 module.exports = ClientCommands;
10
11 ClientCommands.prototype.run = function (command, args, irc_connection, callback) {
12 // Do we have a function to handle this command?
13 if (!listeners[command.toUpperCase()]) {
14 return;
15 }
16
17 return listeners[command.toUpperCase()](args, irc_connection, callback);
18 };
19
20 ClientCommands.prototype.addRpcEvents = function(client, rpc) {
21 // Called for each RPC call
22 // addRpcMethod() below prepends the incoming RPC call with the method name and
23 // the listener that handles this call, and passes that argument list to moduleEventWrap().
24 // This gives us the chance to wrap all calls with connection_id checks and passing
25 // them off to the module system.
26
27 var moduleEventWrap = function(rpc_method, the_fn, callback, connection_id) {
28 var connection, rpc_args, fn_args;
29
30 // Make sure we have a connection_id specified
31 if (!connection_id && connection_id !== 0) {
32 return callback('server not specified');
33
34 } else if (!client.state.irc_connections[connection_id]) {
35 return callback('not connected to server');
36 }
37
38 // The server this command is directed to
39 connection = client.state.irc_connections[connection_id];
40
41 // Get the arguments for the RPC call only (starts at 4)
42 rpc_args = Array.prototype.slice.call(arguments, 4);
43
44 global.modules.emit('rpc ' + rpc_method, {
45 arguments: rpc_args,
46 client: client,
47 connection: connection
48 })
49 .then(function() {
50 // Listeners expect arguments in a (connection, callback, args..n) format, so preppend
51 // the connection + callback
52 fn_args = rpc_args.slice(0);
53 fn_args.unshift(connection, callback);
54
55 the_fn.apply(client, fn_args);
56 }, function() {
57 // The RPC call was prevented from running by a module
58 });
59 };
60
61 // Quick + easier way to call the above function
62 var addRpcMethod = function(rpc_method, fn) {
63 rpc.on(rpc_method, _.partial(moduleEventWrap, rpc_method, fn));
64 };
65
66 addRpcMethod('irc.privmsg', listeners.privmsg);
67 addRpcMethod('irc.ctcp', listeners.ctcp);
68 addRpcMethod('irc.raw', listeners.raw);
69 addRpcMethod('irc.join', listeners.join);
70 addRpcMethod('irc.channel_info', listeners.channel_info);
71 addRpcMethod('irc.part', listeners.part);
72 addRpcMethod('irc.topic', listeners.topic);
73 addRpcMethod('irc.kick', listeners.kick);
74 addRpcMethod('irc.quit', listeners.quit);
75 addRpcMethod('irc.notice', listeners.notice);
76 addRpcMethod('irc.mode', listeners.mode);
77 addRpcMethod('irc.nick', listeners.nick);
78 addRpcMethod('irc.kiwi', listeners.kiwi);
79 addRpcMethod('irc.encoding', listeners.encoding);
80 };
81
82
83
84
85 /**
86 * Truncate a string into blocks of a set size
87 */
88 function truncateString(str, block_size) {
89 block_size = block_size || 350;
90
91 var blocks = [],
92 current_pos;
93
94 for (current_pos = 0; current_pos < str.length; current_pos = current_pos + block_size) {
95 blocks.push(str.substr(current_pos, block_size));
96 }
97
98 return blocks;
99 }
100
101
102
103
104 var listeners = {
105 privmsg: function (irc_connection, callback, args) {
106 // Maximum length of target + message we can send to the IRC server is 500 characters
107 // but we need to leave extra room for the sender prefix so the entire message can
108 // be sent from the IRCd to the target without being truncated.
109 var blocks = truncateString(args.msg, 350);
110
111 blocks.forEach(function (block, idx) {
112 // Apply the callback on the last message only
113 var cb = (idx === blocks.length - 1) ?
114 callback :
115 undefined;
116
117 irc_connection.write('PRIVMSG ' + args.target + ' :' + block, cb);
118 });
119 },
120
121
122 ctcp: function (irc_connection, callback, args) {
123 if ((args.target) && (args.type)) {
124 if (args.is_request) {
125 irc_connection.write('PRIVMSG ' + args.target + ' :' + String.fromCharCode(1) + args.type.toUpperCase() + ' ' + args.params + String.fromCharCode(1), callback);
126 } else {
127 irc_connection.write('NOTICE ' + args.target + ' :' + String.fromCharCode(1) + args.type.toUpperCase() + ' ' + args.params + String.fromCharCode(1), callback);
128 }
129 }
130 },
131
132
133 raw: function (irc_connection, callback, args) {
134 irc_connection.write(args.data, callback);
135 },
136
137
138 join: function (irc_connection, callback, args) {
139 var channels, keys;
140 if (args.channel) {
141 channels = args.channel.split(",");
142 keys = (args.key) ? args.key.split(",") : [];
143 _.each(channels, function (chan, index) {
144 irc_connection.write('JOIN ' + chan + ' ' + (keys[index] || ''), callback);
145 });
146 }
147 },
148
149
150 channel_info: function (irc_connection, callback, args) {
151 if (args.channel) {
152 irc_connection.write('MODE ' + args.channel, callback);
153 }
154 },
155
156
157 part: function (irc_connection, callback, args) {
158 if (args.channel) {
159 _.each(args.channel.split(","), function (chan) {
160 irc_connection.write('PART ' + chan + (args.message ? ' :' + args.message : ''), callback);
161 });
162 }
163 },
164
165
166 topic: function (irc_connection, callback, args) {
167 if (args.channel) {
168 if (args.topic) {
169 irc_connection.write('TOPIC ' + args.channel + ' :' + args.topic, callback);
170 } else {
171 irc_connection.write('TOPIC ' + args.channel, callback);
172 }
173 }
174 },
175
176
177 kick: function (irc_connection, callback, args) {
178 if ((args.channel) && (args.nick)) {
179 irc_connection.write('KICK ' + args.channel + ' ' + args.nick + ' :' + args.reason, callback);
180 }
181 },
182
183
184 quit: function (irc_connection, callback, args) {
185 irc_connection.end('QUIT :' + (args.message||''));
186 },
187
188
189 notice: function (irc_connection, callback, args) {
190 // Maximum length of target + message we can send to the IRC server is 500 characters
191 // but we need to leave extra room for the sender prefix so the entire message can
192 // be sent from the IRCd to the target without being truncated.
193
194 var blocks = truncateString(args.msg, 350);
195 blocks.forEach(function (block, idx) {
196 // Apply the callback on the last message only
197 var cb = (idx === blocks.length - 1) ?
198 callback :
199 undefined;
200
201 irc_connection.write('NOTICE ' + args.target + ' :' + block, cb);
202 });
203 },
204
205
206 mode: function (irc_connection, callback, args) {
207 if ((args.target) && (args.mode)) {
208 irc_connection.write('MODE ' + args.target + ' ' + args.mode + ' ' + args.params, callback);
209 }
210 },
211
212
213 nick: function (irc_connection, callback, args) {
214 if (args.nick) {
215 irc_connection.write('NICK ' + args.nick, callback);
216 }
217 },
218
219
220 kiwi: function (irc_connection, callback, args) {
221 if ((args.target) && (args.data)) {
222 irc_connection.write('PRIVMSG ' + args.target + ': ' + String.fromCharCode(1) + 'KIWI ' + args.data + String.fromCharCode(1), callback);
223 }
224 },
225
226 encoding: function (irc_connection, callback, args) {
227 if (args.encoding) {
228 return callback(irc_connection.setEncoding(args.encoding));
229 }
230 }
231 };