ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/channels.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (16 years, 9 months 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

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