ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/channels.C
Revision: 1.5
Committed: Thu Aug 30 06:57:25 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.4: +9 -7 lines
Log Message:
- chanlist to std::map

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