]> git.lizzy.rs Git - luairc.git/blob - src/irc/channel.lua
document the channel mode methods
[luairc.git] / src / irc / channel.lua
1 ---
2 -- Implementation of the Channel class
3
4 -- initialization {{{
5 local base =   _G
6 local irc =    require 'irc'
7 local misc =   require 'irc.misc'
8 local socket = require 'socket'
9 local table =  require 'table'
10 -- }}}
11
12 ---
13 -- This module implements a channel object representing a single channel we
14 -- have joined
15 -- @release 0.02
16 module 'irc.channel'
17
18 -- object metatable {{{
19 -- TODO: this <br /> shouldn't be necessary - bug in luadoc
20 ---
21 -- An object of the Channel class represents a single joined channel. It has
22 -- several table fields, and can be used in string contexts (returning the
23 -- channel name).<br />
24 -- @class table
25 -- @name Channel
26 -- @field name     Name of the channel (read only)
27 -- @field topic    Channel topic, if set (read/write, writing to this sends a
28 --                 topic change request to the server for this channel)
29 -- @field chanmode Channel mode (public/private/secret) (read only)
30 -- @field members  Array of all members of this channel
31 local mt = {
32     -- __index() {{{
33     __index =    function(self, key)
34                      if key == "name" then
35                          return self._name
36                      elseif key == "topic" then
37                          return self._topic
38                      elseif key == "chanmode" then
39                          return self._chanmode
40                      else
41                          return _M[key]
42                      end
43                  end,
44     -- }}}
45     -- __newindex() {{{
46     __newindex = function(self, key, value)
47                      if key == "name" then
48                          return
49                      elseif key == "topic" then
50                          irc.send("TOPIC", self._name, value)
51                      elseif key == "chanmode" then
52                          return
53                      else
54                          base.rawset(self, key, value)
55                      end
56                  end,
57     -- }}}
58     -- __concat() {{{
59     __concat =   function(first, second)
60                      local first_str, second_str
61
62                      if base.type(first) == "table" then
63                          first_str = first._name
64                      else
65                          first_str = first
66                      end
67                      if base.type(second) == "table" then
68                          second_str = second._name
69                      else
70                          second_str = second
71                      end
72
73                      return first_str .. second_str
74                  end,
75     -- }}}
76     -- __tostring() {{{
77     __tostring = function(self)
78                      return self._name
79                  end
80     -- }}}
81 }
82 -- }}}
83
84 -- private methods {{{
85 -- set_basic_mode {{{
86 --
87 -- Sets a no-arg mode on a channel.
88 -- @name chan:set_basic_mode
89 -- @param self   Channel object
90 -- @param set    True to set the mode, false to unset it
91 -- @param letter Letter of the mode
92 local function set_basic_mode(self, set, letter)
93     if set then
94         irc.send("MODE", self.name, "+" .. letter)
95     else
96         irc.send("MODE", self.name, "-" .. letter)
97     end
98 end
99 -- }}}
100 -- }}}
101
102 -- constructor {{{
103 ---
104 -- Creates a new Channel object.
105 -- @param chan Name of the new channel
106 -- @return The new channel instance
107 function new(chan)
108     return base.setmetatable({_name = chan, _topic = {}, _chanmode = "",
109                               _members = {}}, mt)
110 end
111 -- }}}
112
113 -- public methods {{{
114 -- iterators {{{
115 -- each_op {{{
116 ---
117 -- Iterator over the ops in the channel
118 -- @param self Channel object
119 function each_op(self)
120     return function(state, arg)
121                return misc.value_iter(state, arg,
122                                       function(v)
123                                           return v:sub(1, 1) == "@"
124                                       end)
125            end,
126            self._members,
127            nil
128 end
129 -- }}}
130
131 -- each_voice {{{
132 ---
133 -- Iterator over the voiced users in the channel
134 -- @param self Channel object
135 function each_voice(self)
136     return function(state, arg)
137                return misc.value_iter(state, arg,
138                                       function(v)
139                                           return v:sub(1, 1) == "+"
140                                       end)
141            end,
142            self._members,
143            nil
144 end
145 -- }}}
146
147 -- each_user {{{
148 ---
149 -- Iterator over the normal users in the channel
150 -- @param self Channel object
151 function each_user(self)
152     return function(state, arg)
153                return misc.value_iter(state, arg,
154                                       function(v)
155                                           return v:sub(1, 1) ~= "@" and
156                                                  v:sub(1, 1) ~= "+"
157                                       end)
158            end,
159            self._members,
160            nil
161 end
162 -- }}}
163
164 -- each_member {{{
165 ---
166 -- Iterator over all users in the channel
167 -- @param self Channel object
168 function each_member(self)
169     return misc.value_iter, self._members, nil
170 end
171 -- }}}
172 -- }}}
173
174 -- return tables of users {{{
175 -- ops {{{
176 ---
177 -- Gets an array of all the ops in the channel.
178 -- @param self Channel object
179 -- @return Array of channel ops
180 function ops(self)
181     local ret = {}
182     for nick in self:each_op() do
183         table.insert(ret, nick)
184     end
185     return ret
186 end
187 -- }}}
188
189 -- voices {{{
190 ---
191 -- Gets an array of all the voiced users in the channel.
192 -- @param self Channel object
193 -- @return Array of channel voiced users
194 function voices(self)
195     local ret = {}
196     for nick in self:each_voice() do
197         table.insert(ret, nick)
198     end
199     return ret
200 end
201 -- }}}
202
203 -- users {{{
204 ---
205 -- Gets an array of all the normal users in the channel.
206 -- @param self Channel object
207 -- @return Array of channel normal users
208 function users(self)
209     local ret = {}
210     for nick in self:each_user() do
211         table.insert(ret, nick)
212     end
213     return ret
214 end
215 -- }}}
216
217 -- members {{{
218 ---
219 -- Gets an array of all the users in the channel.
220 -- @param self Channel object
221 -- @return Array of channel users
222 function members(self)
223     local ret = {}
224     -- not just returning self._members, since the return value shouldn't be
225     -- modifiable
226     for nick in self:each_member() do
227         table.insert(ret, nick)
228     end
229     return ret
230 end
231 -- }}}
232 -- }}}
233
234 -- setting modes {{{
235 -- ban {{{
236 -- TODO: hmmm, this probably needs an appropriate mask, rather than a nick
237 ---
238 -- Ban a user from a channel.
239 -- @param self Channel object
240 -- @param name User to ban
241 function ban(self, name)
242     irc.send("MODE", self.name, "+b", name)
243 end
244 -- }}}
245
246 -- unban {{{
247 -- TODO: same here
248 ---
249 -- Remove a ban on a user.
250 -- @param self Channel object
251 -- @param name User to unban
252 function unban(self, name)
253     irc.send("MODE", self.name, "-b", name)
254 end
255 -- }}}
256
257 -- voice {{{
258 ---
259 -- Give a user voice on a channel.
260 -- @param self Channel object
261 -- @param name User to give voice to
262 function voice(self, name)
263     irc.send("MODE", self.name, "+v", name)
264 end
265 -- }}}
266
267 -- devoice {{{
268 ---
269 -- Remove voice from a user.
270 -- @param self Channel object
271 -- @param name User to remove voice from
272 function devoice(self, name)
273     irc.send("MODE", self.name, "-v", name)
274 end
275 -- }}}
276
277 -- op {{{
278 ---
279 -- Give a user ops on a channel.
280 -- @param self Channel object
281 -- @param name User to op
282 function op(self, name)
283     irc.send("MODE", self.name, "+o", name)
284 end
285 -- }}}
286
287 -- deop {{{
288 ---
289 -- Remove ops from a user.
290 -- @param self Channel object
291 -- @param name User to remove ops from
292 function deop(self, name)
293     irc.send("MODE", self.name, "-o", name)
294 end
295 -- }}}
296
297 -- set_limit {{{
298 ---
299 -- Set a channel limit.
300 -- @param self      Channel object
301 -- @param new_limit New value for the channel limit (optional; limit is unset
302 --                  if this argument isn't passed)
303 function set_limit(self, new_limit)
304     if new_limit then
305         irc.send("MODE", self.name, "+l", new_limit)
306     else
307         irc.send("MODE", self.name, "-l")
308     end
309 end
310 -- }}}
311
312 -- set_key {{{
313 ---
314 -- Set a channel password.
315 -- @param self Channel object
316 -- @param key  New channel password (optional; password is unset if this
317 --             argument isn't passed)
318 function set_key(self, key)
319     if key then
320         irc.send("MODE", self.name, "+k", key)
321     else
322         irc.send("MODE", self.name, "-k")
323     end
324 end
325 -- }}}
326
327 -- set_private() {{{
328 ---
329 -- Set the private state of a channel.
330 -- @param self Channel object
331 -- @param set  True to set the channel as private, false to unset it
332 function set_private(self, set)
333     set_basic_mode(self, set, "p")
334 end
335 -- }}}
336
337 -- set_secret {{{
338 ---
339 -- Set the secret state of a channel.
340 -- @param self Channel object
341 -- @param set  True to set the channel as secret, false to unset it
342 function set_secret(self, set)
343     set_basic_mode(self, set, "s")
344 end
345 -- }}}
346
347 -- set_invite_only {{{
348 ---
349 -- Set whether joining the channel requires an invite.
350 -- @param self Channel object
351 -- @param set  True to set the channel invite only, false to unset it
352 function set_invite_only(self, set)
353     set_basic_mode(self, set, "i")
354 end
355 -- }}}
356
357 -- set_topic_lock {{{
358 ---
359 -- If true, the topic can only be changed by an op.
360 -- @param self Channel object
361 -- @param set  True to lock the topic, false to unlock it
362 function set_topic_lock(self, set)
363     set_basic_mode(self, set, "t")
364 end
365 -- }}}
366
367 -- set_no_outside_messages {{{
368 ---
369 -- If true, users must be in the channel to send messages to it.
370 -- @param self Channel object
371 -- @param set  True to require users to be in the channel to send messages to
372 --             it, false to remove this restriction
373 function set_no_outside_messages(self, set)
374     set_basic_mode(self, set, "n")
375 end
376 -- }}}
377
378 -- set moderated {{{
379 ---
380 -- Set whether voice is required to speak.
381 -- @param self Channel object
382 -- @param set  True to set the channel as moderated, false to unset it
383 function set_moderated(self, set)
384     set_basic_mode(self, set, "m")
385 end
386 -- }}}
387 -- }}}
388
389 -- accessors {{{
390 -- add_user() {{{
391 function add_user(self, user, mode)
392     mode = mode or ''
393     self._members[user] = mode .. user
394 end
395 -- }}}
396
397 -- remove_user() {{{
398 function remove_user(self, user)
399     self._members[user] = nil
400 end
401 -- }}}
402
403 -- change_status() {{{
404 function change_status(self, user, on, mode)
405     if on then
406         if mode == 'o' then
407             self._members[user] = '@' .. user
408         elseif mode == 'v' then
409             self._members[user] = '+' .. user
410         end
411     else
412         if (mode == 'o' and self._members[user]:sub(1, 1) == '@') or
413            (mode == 'v' and self._members[user]:sub(1, 1) == '+') then
414             self._members[user] = user
415         end
416     end
417 end
418 -- }}}
419
420 -- contains() {{{
421 function contains(self, nick)
422     for member in self:each_member() do
423         local member_nick = member:gsub('@+', '')
424         if member_nick == nick then
425             return true
426         end
427     end
428     return false
429 end
430 -- }}}
431
432 -- change_nick {{{
433 function change_nick(self, old_nick, new_nick)
434     for member in self:each_member() do
435         local member_nick = member:gsub('@+', '')
436         if member_nick == old_nick then
437             local mode = self._members[old_nick]:sub(1, 1)
438             if mode ~= '@' and mode ~= '+' then mode = "" end
439             self._members[old_nick] = nil
440             self._members[new_nick] = mode .. new_nick
441             break
442         end
443     end
444 end
445 -- }}}
446 -- }}}
447 -- }}}