ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/channels.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +2 -1 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * channels.C: Channel event and state tracking
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
5 pippijn 1.4 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 pippijn 1.1 */
7    
8 pippijn 1.7 static char const rcsid[] = "$Id: channels.C,v 1.6 2007-08-30 19:56:24 pippijn Exp $";
9 pippijn 1.1
10     #include "atheme.h"
11 pippijn 1.7 #include "servers.h"
12 pippijn 1.1 #include <account/mychan.h>
13    
14 pippijn 1.5 channel_map chanlist;
15 pippijn 1.4 channel_t::callbacks channel_t::callback;
16     chanuser_t::callbacks chanuser_t::callback;
17 pippijn 1.1
18     /*
19     * init_channels()
20     *
21     * Initializes the channel-related heaps and DTree structures.
22     *
23     * Inputs:
24     * - nothing
25     *
26     * Outputs:
27     * - nothing
28     *
29     * Side Effects:
30     * - if the heaps or DTrees fail to initialize, the program will abort.
31     */
32     void
33     init_channels (void)
34     {
35 pippijn 1.4 #if 0
36 pippijn 1.1 chan_heap = BlockHeapCreate (sizeof (channel_t), HEAP_CHANNEL);
37     chanuser_heap = BlockHeapCreate (sizeof (chanuser_t), HEAP_CHANUSER);
38     chanban_heap = BlockHeapCreate (sizeof (chanban_t), HEAP_CHANUSER);
39 pippijn 1.4 #endif
40 pippijn 1.1 }
41    
42     /*
43 pippijn 1.4 * channel_add(char const * const name, unsigned int ts, server_t *creator)
44 pippijn 1.1 *
45     * Channel object factory.
46     *
47     * Inputs:
48     * - channel name
49     * - timestamp of channel creation
50     * - server that is creating the channel
51     *
52     * Outputs:
53     * - on success, a channel object
54     * - on failure, NULL
55     *
56     * Side Effects:
57     * - the channel is automatically inserted into the channel DTree
58     * - if the creator is not me.me:
59     * - channel_add hook is called
60     * - all services are joined if this is the snoop channel
61     * - if the creator is me.me these actions must be performed by the
62     * caller (i.e. join()) after joining the service
63     */
64     channel_t *
65 pippijn 1.4 channel_add (char const * const name, unsigned int ts, server_t *creator)
66 pippijn 1.1 {
67     channel_t *c;
68     mychan_t *mc;
69    
70     if (*name != '#')
71     {
72     slog (LG_DEBUG, "channel_add(): got non #channel: %s", name);
73     return NULL;
74     }
75    
76     c = channel_find (name);
77    
78     if (c)
79     {
80     slog (LG_DEBUG, "channel_add(): channel already exists: %s", name);
81     return c;
82     }
83    
84     slog (LG_DEBUG, "channel_add(): %s by %s", name, creator->name);
85    
86 pippijn 1.4 c = new channel_t;
87 pippijn 1.1
88     c->name = sstrdup (name);
89     c->ts = ts;
90    
91     c->topic = NULL;
92     c->topic_setter = NULL;
93    
94     c->bans.head = NULL;
95     c->bans.tail = NULL;
96     c->bans.count = 0;
97    
98 pippijn 1.6 if ((mc = mychan_t::find (c->name)))
99 pippijn 1.1 mc->chan = c;
100    
101 pippijn 1.5 chanlist[c->name] = c;
102 pippijn 1.1
103     cnt.chan++;
104    
105     if (creator != me.me)
106     {
107 pippijn 1.4 c->callback.add (c);
108 pippijn 1.1
109     if (config_options.chan != NULL && !irccasecmp (config_options.chan, name))
110     joinall (config_options.chan);
111     }
112    
113     return c;
114     }
115    
116     /*
117     * channel_delete(channel_t *c)
118     *
119     * Destroys a channel object and its children member objects.
120     *
121     * Inputs:
122     * - channel object to destroy
123     *
124     * Outputs:
125     * - nothing
126     *
127     * Side Effects:
128     * - channel_delete hook is called
129     * - a channel and all attached structures are destroyed
130     * - no protocol messages are sent for any remaining members
131     */
132     void
133     channel_delete (channel_t *c)
134     {
135     mychan_t *mc;
136     node_t *n, *tn;
137     chanuser_t *cu;
138    
139     return_if_fail (c != NULL);
140    
141     slog (LG_DEBUG, "channel_delete(): %s", c->name);
142    
143     modestack_finalize_channel (c);
144    
145     /* If this is called from uplink_close(), there may still be services
146     * in the channel. Remove them. Calling chanuser_delete() could lead
147     * to a recursive call, so don't do that.
148     * -- jilles */
149     LIST_FOREACH_SAFE (n, tn, c->members.head)
150     {
151     cu = static_cast<chanuser_t *> (n->data);
152     soft_assert (is_internal_client (cu->user) && !me.connected);
153     node_del (&cu->cnode, &c->members);
154     node_del (&cu->unode, &cu->user->channels);
155 pippijn 1.4 delete cu;
156 pippijn 1.1 cnt.chanuser--;
157     }
158     c->nummembers = 0;
159    
160 pippijn 1.4 c->callback.remove (c);
161 pippijn 1.1
162 pippijn 1.5 chanlist.erase (c->name);
163 pippijn 1.1
164 pippijn 1.6 if ((mc = mychan_t::find (c->name)))
165 pippijn 1.1 mc->chan = NULL;
166    
167     clear_simple_modes (c);
168     chanban_clear (c);
169    
170 pippijn 1.4 sfree (c->name);
171 pippijn 1.1 if (c->topic != NULL)
172 pippijn 1.4 sfree (c->topic);
173 pippijn 1.1 if (c->topic_setter != NULL)
174 pippijn 1.4 sfree (c->topic_setter);
175 pippijn 1.1
176 pippijn 1.4 delete c;
177 pippijn 1.1
178     cnt.chan--;
179     }
180    
181     /*
182 pippijn 1.4 * channel_find(char const * const name)
183 pippijn 1.1 *
184     * Looks up a channel object.
185     *
186     * Inputs:
187     * - name of channel to look up
188     *
189     * Outputs:
190     * - on success, the channel object
191     * - on failure, NULL
192     *
193     * Side Effects:
194     * - none
195     */
196     channel_t *
197 pippijn 1.4 channel_find (char const * const name)
198 pippijn 1.1 {
199 pippijn 1.5 channel_map::iterator it = chanlist.find (name);
200     if (it == chanlist.end ())
201     return NULL;
202    
203     return it->second;
204 pippijn 1.1 }
205    
206     /*
207 pippijn 1.4 * chanban_add(channel_t *c, char const * const mask, int type)
208 pippijn 1.1 *
209     * Channel ban factory.
210     *
211     * Inputs:
212     * - channel that the ban belongs to
213     * - banmask
214     * - type of ban, e.g. 'b' or 'e'
215     *
216     * Outputs:
217     * - on success, a new channel ban object
218     * - on failure, NULL
219     *
220     * Side Effects:
221     * - the created channel ban object is added to the channel automatically.
222     */
223     chanban_t *
224 pippijn 1.4 chanban_add (channel_t *c, char const * const mask, int type)
225 pippijn 1.1 {
226 pippijn 1.4 chanban_t *cb;
227 pippijn 1.1 node_t *n;
228    
229     if (mask == NULL)
230     {
231     slog (LG_ERROR, "chanban_add(): NULL +%c mask", type);
232     return NULL;
233     }
234     /* this would break protocol and/or cause crashes */
235     if (*mask == '\0' || *mask == ':' || strchr (mask, ' '))
236     {
237 pippijn 1.4 slog (LG_ERROR, "chanban_add(): trying to add invalid +%c %s to channel %s", type, mask, c->name);
238 pippijn 1.1 return NULL;
239     }
240    
241 pippijn 1.4 cb = chanban_find (c, mask, type);
242 pippijn 1.1
243 pippijn 1.4 if (cb)
244 pippijn 1.1 {
245 pippijn 1.4 slog (LG_DEBUG, "chanban_add(): channel ban %s:%s already exists", c->name, cb->mask);
246 pippijn 1.1 return NULL;
247     }
248    
249 pippijn 1.4 slog (LG_DEBUG, "chanban_add(): %s +%c %s", c->name, type, mask);
250 pippijn 1.1
251     n = node_create ();
252 pippijn 1.4 cb = new chanban_t;
253 pippijn 1.1
254 pippijn 1.4 cb->chan = c;
255     cb->mask = sstrdup (mask);
256     cb->type = type;
257 pippijn 1.1
258 pippijn 1.4 node_add (cb, n, &c->bans);
259 pippijn 1.1
260 pippijn 1.4 return cb;
261 pippijn 1.1 }
262    
263     /*
264     * chanban_delete(chanban_t *c)
265     *
266     * Destroys a channel ban.
267     *
268     * Inputs:
269     * - channel ban object to destroy
270     *
271     * Outputs:
272     * - nothing
273     *
274     * Side Effects:
275     * - the channel ban is automatically removed from the channel that owned it
276     */
277     void
278     chanban_delete (chanban_t *c)
279     {
280     node_t *n;
281    
282     if (!c)
283     {
284     slog (LG_DEBUG, "chanban_delete(): called for nonexistant ban");
285     return;
286     }
287    
288     n = node_find (c, &c->chan->bans);
289     node_del (n, &c->chan->bans);
290     node_free (n);
291    
292 pippijn 1.4 sfree (c->mask);
293     delete c;
294 pippijn 1.1 }
295    
296     /*
297 pippijn 1.4 * chanban_find(channel_t *chan, char const * const mask, int type)
298 pippijn 1.1 *
299     * Looks up a channel ban.
300     *
301     * Inputs:
302     * - channel that the ban is supposedly on
303     * - mask that is being looked for
304     * - type of ban that is being looked for
305     *
306     * Outputs:
307     * - on success, returns the channel ban object requested
308     * - on failure, returns NULL
309     *
310     * Side Effects:
311     * - none
312     */
313     chanban_t *
314 pippijn 1.4 chanban_find (channel_t *c, char const * const mask, int type)
315 pippijn 1.1 {
316     chanban_t *cb;
317     node_t *n;
318    
319 pippijn 1.4 LIST_FOREACH (n, c->bans.head)
320 pippijn 1.1 {
321     cb = static_cast<chanban_t *> (n->data);
322    
323     if (cb->type == type && !irccasecmp (cb->mask, mask))
324     return cb;
325     }
326    
327     return NULL;
328     }
329    
330     /*
331 pippijn 1.4 * chanban_clear(channel_t *c)
332 pippijn 1.1 *
333     * Destroys all channel bans attached to a channel.
334     *
335     * Inputs:
336     * - channel to clear banlist on
337     *
338     * Outputs:
339     * - nothing
340     *
341     * Side Effects:
342     * - the banlist on the channel is cleared
343     * - no protocol messages are sent
344     */
345     void
346 pippijn 1.4 chanban_clear (channel_t *c)
347 pippijn 1.1 {
348     node_t *n, *tn;
349    
350 pippijn 1.4 LIST_FOREACH_SAFE (n, tn, c->bans.head)
351 pippijn 1.1 {
352     /* inefficient but avoids code duplication -- jilles */
353     chanban_delete (static_cast<chanban_t *> (n->data));
354     }
355     }
356    
357     /*
358 pippijn 1.4 * chanuser_add(channel_t *c, char const * const nick)
359 pippijn 1.1 *
360     * Channel user factory.
361     *
362     * Inputs:
363     * - channel that the user should belong to
364     * - nick/UID with any appropriate prefixes (e.g. ~, &, @, %, +)
365     * (if the user has a UID it must be used)
366     *
367     * Outputs:
368     * - on success, a new channel user object
369     * - on failure (NULL channel, or user kicked by channel_join hook), NULL
370     *
371     * Side Effects:
372     * - the channel user object is automatically associated to its parents
373     * - channel_join hook is called
374     */
375    
376     /*
377     * Rewritten 06/23/05 by nenolod:
378     *
379     * Iterate through the list of prefix characters we know about.
380     * Continue to do so until all prefixes are covered. Then add the
381     * nick to the channel, with the privs he has acquired thus far.
382     *
383     * Once, and only once we have done that do we start in on checking
384     * privileges. Otherwise we have a very inefficient way of doing
385     * things. It worked fine for shrike, but the old code was restricted
386     * to handling only @, @+ and + as prefixes.
387     */
388     chanuser_t *
389 pippijn 1.4 chanuser_add (channel_t *c, char const * const nickname)
390 pippijn 1.1 {
391 pippijn 1.4 char const *nick = nickname;
392 pippijn 1.1 user_t *u;
393     chanuser_t *cu, *tcu;
394     unsigned int flags = 0;
395     int i = 0;
396    
397 pippijn 1.4 if (c == NULL)
398 pippijn 1.1 return NULL;
399    
400 pippijn 1.4 if (*c->name != '#')
401 pippijn 1.1 {
402 pippijn 1.4 slog (LG_DEBUG, "chanuser_add(): got non #channel: %s", c->name);
403 pippijn 1.1 return NULL;
404     }
405    
406     while (*nick != '\0')
407     {
408     for (i = 0; prefix_mode_list[i].mode; i++)
409     if (*nick == prefix_mode_list[i].mode)
410     {
411     flags |= prefix_mode_list[i].value;
412     break;
413     }
414     if (!prefix_mode_list[i].mode)
415     break;
416     nick++;
417     }
418    
419     u = user_find (nick);
420     if (u == NULL)
421     {
422     slog (LG_DEBUG, "chanuser_add(): nonexist user: %s", nick);
423     return NULL;
424     }
425    
426 pippijn 1.4 tcu = chanuser_find (c, u);
427 pippijn 1.1 if (tcu != NULL)
428     {
429 pippijn 1.4 slog (LG_DEBUG, "chanuser_add(): user is already present: %s -> %s", c->name, u->nick);
430 pippijn 1.1
431     /* could be an OPME or other desyncher... */
432     tcu->modes |= flags;
433    
434     return tcu;
435     }
436    
437 pippijn 1.4 slog (LG_DEBUG, "chanuser_add(): %s -> %s", c->name, u->nick);
438 pippijn 1.1
439 pippijn 1.4 cu = new chanuser_t;
440 pippijn 1.1
441 pippijn 1.4 cu->chan = c;
442 pippijn 1.1 cu->user = u;
443     cu->modes |= flags;
444    
445 pippijn 1.4 c->nummembers++;
446 pippijn 1.1
447 pippijn 1.4 node_add (cu, &cu->cnode, &c->members);
448 pippijn 1.1 node_add (cu, &cu->unode, &u->channels);
449    
450     cnt.chanuser++;
451    
452     /* Return NULL if a hook function kicked the user out */
453 pippijn 1.4 return cu->callback.join (cu) ? cu : NULL;
454 pippijn 1.1 }
455    
456     /*
457 pippijn 1.4 * chanuser_delete(channel_t *c, user_t *user)
458 pippijn 1.1 *
459     * Destroys a channel user object.
460     *
461     * Inputs:
462     * - channel the user is on
463     * - the user itself
464     *
465     * Outputs:
466     * - nothing
467     *
468     * Side Effects:
469     * if the user is on the channel:
470     * - a channel user object is removed from the
471     * channel's userlist and the user's channellist.
472     * - channel_part hook is called
473     * - if this empties the channel and the channel is not set permanent
474     * (ircd->perm_mode), channel_delete() is called (q.v.)
475     */
476     void
477 pippijn 1.4 chanuser_delete (channel_t *c, user_t *user)
478 pippijn 1.1 {
479     chanuser_t *cu;
480    
481 pippijn 1.4 if (!c)
482 pippijn 1.1 {
483     slog (LG_DEBUG, "chanuser_delete(): called with NULL chan");
484     return;
485     }
486    
487     if (!user)
488     {
489     slog (LG_DEBUG, "chanuser_delete(): called with NULL user");
490     return;
491     }
492    
493 pippijn 1.4 cu = chanuser_find (c, user);
494 pippijn 1.1 if (cu == NULL)
495     return;
496    
497     /* this is called BEFORE we remove the user */
498 pippijn 1.4 cu->callback.part (cu);
499 pippijn 1.1
500     slog (LG_DEBUG, "chanuser_delete(): %s -> %s (%d)", cu->chan->name, cu->user->nick, cu->chan->nummembers - 1);
501    
502 pippijn 1.4 node_del (&cu->cnode, &c->members);
503 pippijn 1.1 node_del (&cu->unode, &user->channels);
504    
505 pippijn 1.4 delete cu;
506 pippijn 1.1
507 pippijn 1.4 c->nummembers--;
508 pippijn 1.1 cnt.chanuser--;
509    
510 pippijn 1.4 if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
511 pippijn 1.1 {
512     /* empty channels die */
513 pippijn 1.4 slog (LG_DEBUG, "chanuser_delete(): `%s' is empty, removing", c->name);
514 pippijn 1.1
515 pippijn 1.4 channel_delete (c);
516 pippijn 1.1 }
517     }
518    
519     /*
520 pippijn 1.4 * chanuser_find(channel_t *c, user_t *user)
521 pippijn 1.1 *
522     * Looks up a channel user object.
523     *
524     * Inputs:
525     * - channel object that the user is on
526     * - target user object
527     *
528     * Outputs:
529     * - on success, a channel user object
530     * - on failure, NULL
531     *
532     * Side Effects:
533     * - none
534     */
535     chanuser_t *
536 pippijn 1.4 chanuser_find (channel_t *c, user_t *user)
537 pippijn 1.1 {
538     node_t *n;
539     chanuser_t *cu;
540    
541 pippijn 1.4 if ((!c) || (!user))
542 pippijn 1.1 return NULL;
543    
544     /* choose shortest list to search -- jilles */
545 pippijn 1.4 if (LIST_LENGTH (&user->channels) < LIST_LENGTH (&c->members))
546 pippijn 1.1 {
547     LIST_FOREACH (n, user->channels.head)
548     {
549     cu = (chanuser_t *) n->data;
550    
551 pippijn 1.4 if (cu->chan == c)
552 pippijn 1.1 return cu;
553     }
554     }
555     else
556     {
557 pippijn 1.4 LIST_FOREACH (n, c->members.head)
558 pippijn 1.1 {
559     cu = (chanuser_t *) n->data;
560    
561     if (cu->user == user)
562     return cu;
563     }
564     }
565    
566     return NULL;
567     }