ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/channels.C
Revision: 1.6
Committed: Thu Aug 30 19:56:24 2007 UTC (16 years, 9 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.5: +3 -3 lines
Log Message:
- put faultcodes into their own namespace
- removed old files
- limited header garbage in atheme.h
- macros to inline bools for connection_t::is_*
- put some connection_t functions into the connection_t class

File Contents

# Content
1 /*
2 * channels.C: Channel event and state tracking
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id: channels.C,v 1.5 2007-08-30 06:57:25 pippijn Exp $";
9
10 #include "atheme.h"
11 #include <account/mychan.h>
12
13 channel_map chanlist;
14 channel_t::callbacks channel_t::callback;
15 chanuser_t::callbacks chanuser_t::callback;
16
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 #if 0
35 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 #endif
39 }
40
41 /*
42 * channel_add(char const * const name, unsigned int ts, server_t *creator)
43 *
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 channel_add (char const * const name, unsigned int ts, server_t *creator)
65 {
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 c = new channel_t;
86
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_t::find (c->name)))
98 mc->chan = c;
99
100 chanlist[c->name] = c;
101
102 cnt.chan++;
103
104 if (creator != me.me)
105 {
106 c->callback.add (c);
107
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 delete cu;
155 cnt.chanuser--;
156 }
157 c->nummembers = 0;
158
159 c->callback.remove (c);
160
161 chanlist.erase (c->name);
162
163 if ((mc = mychan_t::find (c->name)))
164 mc->chan = NULL;
165
166 clear_simple_modes (c);
167 chanban_clear (c);
168
169 sfree (c->name);
170 if (c->topic != NULL)
171 sfree (c->topic);
172 if (c->topic_setter != NULL)
173 sfree (c->topic_setter);
174
175 delete c;
176
177 cnt.chan--;
178 }
179
180 /*
181 * channel_find(char const * const name)
182 *
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 channel_find (char const * const name)
197 {
198 channel_map::iterator it = chanlist.find (name);
199 if (it == chanlist.end ())
200 return NULL;
201
202 return it->second;
203 }
204
205 /*
206 * chanban_add(channel_t *c, char const * const mask, int type)
207 *
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 chanban_add (channel_t *c, char const * const mask, int type)
224 {
225 chanban_t *cb;
226 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 slog (LG_ERROR, "chanban_add(): trying to add invalid +%c %s to channel %s", type, mask, c->name);
237 return NULL;
238 }
239
240 cb = chanban_find (c, mask, type);
241
242 if (cb)
243 {
244 slog (LG_DEBUG, "chanban_add(): channel ban %s:%s already exists", c->name, cb->mask);
245 return NULL;
246 }
247
248 slog (LG_DEBUG, "chanban_add(): %s +%c %s", c->name, type, mask);
249
250 n = node_create ();
251 cb = new chanban_t;
252
253 cb->chan = c;
254 cb->mask = sstrdup (mask);
255 cb->type = type;
256
257 node_add (cb, n, &c->bans);
258
259 return cb;
260 }
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 sfree (c->mask);
292 delete c;
293 }
294
295 /*
296 * chanban_find(channel_t *chan, char const * const mask, int type)
297 *
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 chanban_find (channel_t *c, char const * const mask, int type)
314 {
315 chanban_t *cb;
316 node_t *n;
317
318 LIST_FOREACH (n, c->bans.head)
319 {
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 * chanban_clear(channel_t *c)
331 *
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 chanban_clear (channel_t *c)
346 {
347 node_t *n, *tn;
348
349 LIST_FOREACH_SAFE (n, tn, c->bans.head)
350 {
351 /* inefficient but avoids code duplication -- jilles */
352 chanban_delete (static_cast<chanban_t *> (n->data));
353 }
354 }
355
356 /*
357 * chanuser_add(channel_t *c, char const * const nick)
358 *
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 chanuser_add (channel_t *c, char const * const nickname)
389 {
390 char const *nick = nickname;
391 user_t *u;
392 chanuser_t *cu, *tcu;
393 unsigned int flags = 0;
394 int i = 0;
395
396 if (c == NULL)
397 return NULL;
398
399 if (*c->name != '#')
400 {
401 slog (LG_DEBUG, "chanuser_add(): got non #channel: %s", c->name);
402 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 tcu = chanuser_find (c, u);
426 if (tcu != NULL)
427 {
428 slog (LG_DEBUG, "chanuser_add(): user is already present: %s -> %s", c->name, u->nick);
429
430 /* could be an OPME or other desyncher... */
431 tcu->modes |= flags;
432
433 return tcu;
434 }
435
436 slog (LG_DEBUG, "chanuser_add(): %s -> %s", c->name, u->nick);
437
438 cu = new chanuser_t;
439
440 cu->chan = c;
441 cu->user = u;
442 cu->modes |= flags;
443
444 c->nummembers++;
445
446 node_add (cu, &cu->cnode, &c->members);
447 node_add (cu, &cu->unode, &u->channels);
448
449 cnt.chanuser++;
450
451 /* Return NULL if a hook function kicked the user out */
452 return cu->callback.join (cu) ? cu : NULL;
453 }
454
455 /*
456 * chanuser_delete(channel_t *c, user_t *user)
457 *
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 chanuser_delete (channel_t *c, user_t *user)
477 {
478 chanuser_t *cu;
479
480 if (!c)
481 {
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 cu = chanuser_find (c, user);
493 if (cu == NULL)
494 return;
495
496 /* this is called BEFORE we remove the user */
497 cu->callback.part (cu);
498
499 slog (LG_DEBUG, "chanuser_delete(): %s -> %s (%d)", cu->chan->name, cu->user->nick, cu->chan->nummembers - 1);
500
501 node_del (&cu->cnode, &c->members);
502 node_del (&cu->unode, &user->channels);
503
504 delete cu;
505
506 c->nummembers--;
507 cnt.chanuser--;
508
509 if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
510 {
511 /* empty channels die */
512 slog (LG_DEBUG, "chanuser_delete(): `%s' is empty, removing", c->name);
513
514 channel_delete (c);
515 }
516 }
517
518 /*
519 * chanuser_find(channel_t *c, user_t *user)
520 *
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 chanuser_find (channel_t *c, user_t *user)
536 {
537 node_t *n;
538 chanuser_t *cu;
539
540 if ((!c) || (!user))
541 return NULL;
542
543 /* choose shortest list to search -- jilles */
544 if (LIST_LENGTH (&user->channels) < LIST_LENGTH (&c->members))
545 {
546 LIST_FOREACH (n, user->channels.head)
547 {
548 cu = (chanuser_t *) n->data;
549
550 if (cu->chan == c)
551 return cu;
552 }
553 }
554 else
555 {
556 LIST_FOREACH (n, c->members.head)
557 {
558 cu = (chanuser_t *) n->data;
559
560 if (cu->user == user)
561 return cu;
562 }
563 }
564
565 return NULL;
566 }