ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/channels.C
(Generate patch)

Comparing ermyth/src/channels.C (file contents):
Revision 1.3 by pippijn, Sat Jul 21 13:23:21 2007 UTC vs.
Revision 1.4 by pippijn, Tue Aug 28 17:08:12 2007 UTC

1/* 1/*
2 * channels.C: Channel event and state tracking 2 * channels.C: Channel event and state tracking
3 * Rights to this code are documented in doc/pod/license.pod. 3 * Rights to this code are documented in doc/pod/license.pod.
4 * 4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) 5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */ 6 */
7 7
8static char const rcsid[] = "$Id: channels.C,v 1.3 2007/07/21 13:23:21 pippijn Exp $"; 8static char const rcsid[] = "$Id: channels.C,v 1.4 2007/08/28 17:08:12 pippijn Exp $";
9 9
10#include "atheme.h" 10#include "atheme.h"
11#include <account/mychan.h> 11#include <account/mychan.h>
12 12
13dictionary_tree_t *chanlist; 13dictionary_tree_t *chanlist;
14 14channel_t::callbacks channel_t::callback;
15static BlockHeap *chan_heap; 15chanuser_t::callbacks chanuser_t::callback;
16static BlockHeap *chanuser_heap;
17static BlockHeap *chanban_heap;
18 16
19/* 17/*
20 * init_channels() 18 * init_channels()
21 * 19 *
22 * Initializes the channel-related heaps and DTree structures. 20 * Initializes the channel-related heaps and DTree structures.
31 * - if the heaps or DTrees fail to initialize, the program will abort. 29 * - if the heaps or DTrees fail to initialize, the program will abort.
32 */ 30 */
33void 31void
34init_channels (void) 32init_channels (void)
35{ 33{
34#if 0
36 chan_heap = BlockHeapCreate (sizeof (channel_t), HEAP_CHANNEL); 35 chan_heap = BlockHeapCreate (sizeof (channel_t), HEAP_CHANNEL);
37 chanuser_heap = BlockHeapCreate (sizeof (chanuser_t), HEAP_CHANUSER); 36 chanuser_heap = BlockHeapCreate (sizeof (chanuser_t), HEAP_CHANUSER);
38 chanban_heap = BlockHeapCreate (sizeof (chanban_t), HEAP_CHANUSER); 37 chanban_heap = BlockHeapCreate (sizeof (chanban_t), HEAP_CHANUSER);
39 38#endif
40 if (chan_heap == NULL || chanuser_heap == NULL || chanban_heap == NULL)
41 {
42 slog (LG_INFO, "init_channels(): block allocator failure.");
43 exit (EXIT_FAILURE);
44 }
45 39
46 chanlist = dictionary_create ("channel", HASH_CHANNEL, irccasecmp); 40 chanlist = dictionary_create ("channel", HASH_CHANNEL, irccasecmp);
47} 41}
48 42
49/* 43/*
50 * channel_add(const char *name, unsigned int ts, server_t *creator) 44 * channel_add(char const * const name, unsigned int ts, server_t *creator)
51 * 45 *
52 * Channel object factory. 46 * Channel object factory.
53 * 47 *
54 * Inputs: 48 * Inputs:
55 * - channel name 49 * - channel name
67 * - all services are joined if this is the snoop channel 61 * - all services are joined if this is the snoop channel
68 * - if the creator is me.me these actions must be performed by the 62 * - if the creator is me.me these actions must be performed by the
69 * caller (i.e. join()) after joining the service 63 * caller (i.e. join()) after joining the service
70 */ 64 */
71channel_t * 65channel_t *
72channel_add (const char *name, unsigned int ts, server_t *creator) 66channel_add (char const * const name, unsigned int ts, server_t *creator)
73{ 67{
74 channel_t *c; 68 channel_t *c;
75 mychan_t *mc; 69 mychan_t *mc;
76 70
77 if (*name != '#') 71 if (*name != '#')
88 return c; 82 return c;
89 } 83 }
90 84
91 slog (LG_DEBUG, "channel_add(): %s by %s", name, creator->name); 85 slog (LG_DEBUG, "channel_add(): %s by %s", name, creator->name);
92 86
93 c = static_cast<channel_t *> (BlockHeapAlloc (chan_heap)); 87 c = new channel_t;
94 88
95 c->name = sstrdup (name); 89 c->name = sstrdup (name);
96 c->ts = ts; 90 c->ts = ts;
97 91
98 c->topic = NULL; 92 c->topic = NULL;
109 103
110 cnt.chan++; 104 cnt.chan++;
111 105
112 if (creator != me.me) 106 if (creator != me.me)
113 { 107 {
114 hook_call_event ("channel_add", c); 108 c->callback.add (c);
115 109
116 if (config_options.chan != NULL && !irccasecmp (config_options.chan, name)) 110 if (config_options.chan != NULL && !irccasecmp (config_options.chan, name))
117 joinall (config_options.chan); 111 joinall (config_options.chan);
118 } 112 }
119 113
157 { 151 {
158 cu = static_cast<chanuser_t *> (n->data); 152 cu = static_cast<chanuser_t *> (n->data);
159 soft_assert (is_internal_client (cu->user) && !me.connected); 153 soft_assert (is_internal_client (cu->user) && !me.connected);
160 node_del (&cu->cnode, &c->members); 154 node_del (&cu->cnode, &c->members);
161 node_del (&cu->unode, &cu->user->channels); 155 node_del (&cu->unode, &cu->user->channels);
162 BlockHeapFree (chanuser_heap, cu); 156 delete cu;
163 cnt.chanuser--; 157 cnt.chanuser--;
164 } 158 }
165 c->nummembers = 0; 159 c->nummembers = 0;
166 160
167 hook_call_event ("channel_delete", c); 161 c->callback.remove (c);
168 162
169 dictionary_delete (chanlist, c->name); 163 dictionary_delete (chanlist, c->name);
170 164
171 if ((mc = mychan_find (c->name))) 165 if ((mc = mychan_find (c->name)))
172 mc->chan = NULL; 166 mc->chan = NULL;
173 167
174 clear_simple_modes (c); 168 clear_simple_modes (c);
175 chanban_clear (c); 169 chanban_clear (c);
176 170
177 free (c->name); 171 sfree (c->name);
178 if (c->topic != NULL) 172 if (c->topic != NULL)
179 free (c->topic); 173 sfree (c->topic);
180 if (c->topic_setter != NULL) 174 if (c->topic_setter != NULL)
181 free (c->topic_setter); 175 sfree (c->topic_setter);
182 176
183 BlockHeapFree (chan_heap, c); 177 delete c;
184 178
185 cnt.chan--; 179 cnt.chan--;
186} 180}
187 181
188/* 182/*
189 * channel_find(const char *name) 183 * channel_find(char const * const name)
190 * 184 *
191 * Looks up a channel object. 185 * Looks up a channel object.
192 * 186 *
193 * Inputs: 187 * Inputs:
194 * - name of channel to look up 188 * - name of channel to look up
199 * 193 *
200 * Side Effects: 194 * Side Effects:
201 * - none 195 * - none
202 */ 196 */
203channel_t * 197channel_t *
204channel_find (const char *name) 198channel_find (char const * const name)
205{ 199{
206 return static_cast<channel_t *> (dictionary_retrieve (chanlist, name)); 200 return static_cast<channel_t *> (dictionary_retrieve (chanlist, name));
207} 201}
208 202
209/* 203/*
210 * chanban_add(channel_t *chan, const char *mask, int type) 204 * chanban_add(channel_t *c, char const * const mask, int type)
211 * 205 *
212 * Channel ban factory. 206 * Channel ban factory.
213 * 207 *
214 * Inputs: 208 * Inputs:
215 * - channel that the ban belongs to 209 * - channel that the ban belongs to
222 * 216 *
223 * Side Effects: 217 * Side Effects:
224 * - the created channel ban object is added to the channel automatically. 218 * - the created channel ban object is added to the channel automatically.
225 */ 219 */
226chanban_t * 220chanban_t *
227chanban_add (channel_t *chan, const char *mask, int type) 221chanban_add (channel_t *c, char const * const mask, int type)
228{ 222{
229 chanban_t *c; 223 chanban_t *cb;
230 node_t *n; 224 node_t *n;
231 225
232 if (mask == NULL) 226 if (mask == NULL)
233 { 227 {
234 slog (LG_ERROR, "chanban_add(): NULL +%c mask", type); 228 slog (LG_ERROR, "chanban_add(): NULL +%c mask", type);
235 return NULL; 229 return NULL;
236 } 230 }
237 /* this would break protocol and/or cause crashes */ 231 /* this would break protocol and/or cause crashes */
238 if (*mask == '\0' || *mask == ':' || strchr (mask, ' ')) 232 if (*mask == '\0' || *mask == ':' || strchr (mask, ' '))
239 { 233 {
240 slog (LG_ERROR, "chanban_add(): trying to add invalid +%c %s to channel %s", type, mask, chan->name); 234 slog (LG_ERROR, "chanban_add(): trying to add invalid +%c %s to channel %s", type, mask, c->name);
241 return NULL; 235 return NULL;
242 } 236 }
243 237
244 c = chanban_find (chan, mask, type); 238 cb = chanban_find (c, mask, type);
245 239
246 if (c) 240 if (cb)
247 { 241 {
248 slog (LG_DEBUG, "chanban_add(): channel ban %s:%s already exists", chan->name, c->mask); 242 slog (LG_DEBUG, "chanban_add(): channel ban %s:%s already exists", c->name, cb->mask);
249 return NULL; 243 return NULL;
250 } 244 }
251 245
252 slog (LG_DEBUG, "chanban_add(): %s +%c %s", chan->name, type, mask); 246 slog (LG_DEBUG, "chanban_add(): %s +%c %s", c->name, type, mask);
253 247
254 n = node_create (); 248 n = node_create ();
255 c = static_cast<chanban_t *> (BlockHeapAlloc (chanban_heap)); 249 cb = new chanban_t;
256 250
257 c->chan = chan; 251 cb->chan = c;
258 c->mask = sstrdup (mask); 252 cb->mask = sstrdup (mask);
259 c->type = type; 253 cb->type = type;
260 254
261 node_add (c, n, &chan->bans); 255 node_add (cb, n, &c->bans);
262 256
263 return c; 257 return cb;
264} 258}
265 259
266/* 260/*
267 * chanban_delete(chanban_t *c) 261 * chanban_delete(chanban_t *c)
268 * 262 *
290 284
291 n = node_find (c, &c->chan->bans); 285 n = node_find (c, &c->chan->bans);
292 node_del (n, &c->chan->bans); 286 node_del (n, &c->chan->bans);
293 node_free (n); 287 node_free (n);
294 288
295 free (c->mask); 289 sfree (c->mask);
296 BlockHeapFree (chanban_heap, c); 290 delete c;
297} 291}
298 292
299/* 293/*
300 * chanban_find(channel_t *chan, const char *mask, int type) 294 * chanban_find(channel_t *chan, char const * const mask, int type)
301 * 295 *
302 * Looks up a channel ban. 296 * Looks up a channel ban.
303 * 297 *
304 * Inputs: 298 * Inputs:
305 * - channel that the ban is supposedly on 299 * - channel that the ban is supposedly on
312 * 306 *
313 * Side Effects: 307 * Side Effects:
314 * - none 308 * - none
315 */ 309 */
316chanban_t * 310chanban_t *
317chanban_find (channel_t *chan, const char *mask, int type) 311chanban_find (channel_t *c, char const * const mask, int type)
318{ 312{
319 chanban_t *cb; 313 chanban_t *cb;
320 node_t *n; 314 node_t *n;
321 315
322 LIST_FOREACH (n, chan->bans.head) 316 LIST_FOREACH (n, c->bans.head)
323 { 317 {
324 cb = static_cast<chanban_t *> (n->data); 318 cb = static_cast<chanban_t *> (n->data);
325 319
326 if (cb->type == type && !irccasecmp (cb->mask, mask)) 320 if (cb->type == type && !irccasecmp (cb->mask, mask))
327 return cb; 321 return cb;
329 323
330 return NULL; 324 return NULL;
331} 325}
332 326
333/* 327/*
334 * chanban_clear(channel_t *chan) 328 * chanban_clear(channel_t *c)
335 * 329 *
336 * Destroys all channel bans attached to a channel. 330 * Destroys all channel bans attached to a channel.
337 * 331 *
338 * Inputs: 332 * Inputs:
339 * - channel to clear banlist on 333 * - channel to clear banlist on
344 * Side Effects: 338 * Side Effects:
345 * - the banlist on the channel is cleared 339 * - the banlist on the channel is cleared
346 * - no protocol messages are sent 340 * - no protocol messages are sent
347 */ 341 */
348void 342void
349chanban_clear (channel_t *chan) 343chanban_clear (channel_t *c)
350{ 344{
351 node_t *n, *tn; 345 node_t *n, *tn;
352 346
353 LIST_FOREACH_SAFE (n, tn, chan->bans.head) 347 LIST_FOREACH_SAFE (n, tn, c->bans.head)
354 { 348 {
355 /* inefficient but avoids code duplication -- jilles */ 349 /* inefficient but avoids code duplication -- jilles */
356 chanban_delete (static_cast<chanban_t *> (n->data)); 350 chanban_delete (static_cast<chanban_t *> (n->data));
357 } 351 }
358} 352}
359 353
360/* 354/*
361 * chanuser_add(channel_t *chan, const char *nick) 355 * chanuser_add(channel_t *c, char const * const nick)
362 * 356 *
363 * Channel user factory. 357 * Channel user factory.
364 * 358 *
365 * Inputs: 359 * Inputs:
366 * - channel that the user should belong to 360 * - channel that the user should belong to
387 * privileges. Otherwise we have a very inefficient way of doing 381 * privileges. Otherwise we have a very inefficient way of doing
388 * things. It worked fine for shrike, but the old code was restricted 382 * things. It worked fine for shrike, but the old code was restricted
389 * to handling only @, @+ and + as prefixes. 383 * to handling only @, @+ and + as prefixes.
390 */ 384 */
391chanuser_t * 385chanuser_t *
392chanuser_add (channel_t *chan, const char *nick) 386chanuser_add (channel_t *c, char const * const nickname)
393{ 387{
388 char const *nick = nickname;
394 user_t *u; 389 user_t *u;
395 chanuser_t *cu, *tcu; 390 chanuser_t *cu, *tcu;
396 unsigned int flags = 0; 391 unsigned int flags = 0;
397 int i = 0; 392 int i = 0;
398 hook_channel_joinpart_t hdata;
399 393
400 if (chan == NULL) 394 if (c == NULL)
401 return NULL; 395 return NULL;
402 396
403 if (*chan->name != '#') 397 if (*c->name != '#')
404 { 398 {
405 slog (LG_DEBUG, "chanuser_add(): got non #channel: %s", chan->name); 399 slog (LG_DEBUG, "chanuser_add(): got non #channel: %s", c->name);
406 return NULL; 400 return NULL;
407 } 401 }
408 402
409 while (*nick != '\0') 403 while (*nick != '\0')
410 { 404 {
424 { 418 {
425 slog (LG_DEBUG, "chanuser_add(): nonexist user: %s", nick); 419 slog (LG_DEBUG, "chanuser_add(): nonexist user: %s", nick);
426 return NULL; 420 return NULL;
427 } 421 }
428 422
429 tcu = chanuser_find (chan, u); 423 tcu = chanuser_find (c, u);
430 if (tcu != NULL) 424 if (tcu != NULL)
431 { 425 {
432 slog (LG_DEBUG, "chanuser_add(): user is already present: %s -> %s", chan->name, u->nick); 426 slog (LG_DEBUG, "chanuser_add(): user is already present: %s -> %s", c->name, u->nick);
433 427
434 /* could be an OPME or other desyncher... */ 428 /* could be an OPME or other desyncher... */
435 tcu->modes |= flags; 429 tcu->modes |= flags;
436 430
437 return tcu; 431 return tcu;
438 } 432 }
439 433
440 slog (LG_DEBUG, "chanuser_add(): %s -> %s", chan->name, u->nick); 434 slog (LG_DEBUG, "chanuser_add(): %s -> %s", c->name, u->nick);
441 435
442 cu = static_cast<chanuser_t *> (BlockHeapAlloc (chanuser_heap)); 436 cu = new chanuser_t;
443 437
444 cu->chan = chan; 438 cu->chan = c;
445 cu->user = u; 439 cu->user = u;
446 cu->modes |= flags; 440 cu->modes |= flags;
447 441
448 chan->nummembers++; 442 c->nummembers++;
449 443
450 node_add (cu, &cu->cnode, &chan->members); 444 node_add (cu, &cu->cnode, &c->members);
451 node_add (cu, &cu->unode, &u->channels); 445 node_add (cu, &cu->unode, &u->channels);
452 446
453 cnt.chanuser++; 447 cnt.chanuser++;
454 448
455 hdata.cu = cu;
456 hook_call_event ("channel_join", &hdata);
457
458 /* Return NULL if a hook function kicked the user out */ 449 /* Return NULL if a hook function kicked the user out */
459 return hdata.cu; 450 return cu->callback.join (cu) ? cu : NULL;
460} 451}
461 452
462/* 453/*
463 * chanuser_delete(channel_t *chan, user_t *user) 454 * chanuser_delete(channel_t *c, user_t *user)
464 * 455 *
465 * Destroys a channel user object. 456 * Destroys a channel user object.
466 * 457 *
467 * Inputs: 458 * Inputs:
468 * - channel the user is on 459 * - channel the user is on
478 * - channel_part hook is called 469 * - channel_part hook is called
479 * - if this empties the channel and the channel is not set permanent 470 * - if this empties the channel and the channel is not set permanent
480 * (ircd->perm_mode), channel_delete() is called (q.v.) 471 * (ircd->perm_mode), channel_delete() is called (q.v.)
481 */ 472 */
482void 473void
483chanuser_delete (channel_t *chan, user_t *user) 474chanuser_delete (channel_t *c, user_t *user)
484{ 475{
485 chanuser_t *cu; 476 chanuser_t *cu;
486 hook_channel_joinpart_t hdata;
487 477
488 if (!chan) 478 if (!c)
489 { 479 {
490 slog (LG_DEBUG, "chanuser_delete(): called with NULL chan"); 480 slog (LG_DEBUG, "chanuser_delete(): called with NULL chan");
491 return; 481 return;
492 } 482 }
493 483
495 { 485 {
496 slog (LG_DEBUG, "chanuser_delete(): called with NULL user"); 486 slog (LG_DEBUG, "chanuser_delete(): called with NULL user");
497 return; 487 return;
498 } 488 }
499 489
500 cu = chanuser_find (chan, user); 490 cu = chanuser_find (c, user);
501 if (cu == NULL) 491 if (cu == NULL)
502 return; 492 return;
503 493
504 /* this is called BEFORE we remove the user */ 494 /* this is called BEFORE we remove the user */
505 hdata.cu = cu; 495 cu->callback.part (cu);
506 hook_call_event ("channel_part", &hdata);
507 496
508 slog (LG_DEBUG, "chanuser_delete(): %s -> %s (%d)", cu->chan->name, cu->user->nick, cu->chan->nummembers - 1); 497 slog (LG_DEBUG, "chanuser_delete(): %s -> %s (%d)", cu->chan->name, cu->user->nick, cu->chan->nummembers - 1);
509 498
510 node_del (&cu->cnode, &chan->members); 499 node_del (&cu->cnode, &c->members);
511 node_del (&cu->unode, &user->channels); 500 node_del (&cu->unode, &user->channels);
512 501
513 BlockHeapFree (chanuser_heap, cu); 502 delete cu;
514 503
515 chan->nummembers--; 504 c->nummembers--;
516 cnt.chanuser--; 505 cnt.chanuser--;
517 506
518 if (chan->nummembers == 0 && !(chan->modes & ircd->perm_mode)) 507 if (c->nummembers == 0 && !(c->modes & ircd->perm_mode))
519 { 508 {
520 /* empty channels die */ 509 /* empty channels die */
521 slog (LG_DEBUG, "chanuser_delete(): `%s' is empty, removing", chan->name); 510 slog (LG_DEBUG, "chanuser_delete(): `%s' is empty, removing", c->name);
522 511
523 channel_delete (chan); 512 channel_delete (c);
524 } 513 }
525} 514}
526 515
527/* 516/*
528 * chanuser_find(channel_t *chan, user_t *user) 517 * chanuser_find(channel_t *c, user_t *user)
529 * 518 *
530 * Looks up a channel user object. 519 * Looks up a channel user object.
531 * 520 *
532 * Inputs: 521 * Inputs:
533 * - channel object that the user is on 522 * - channel object that the user is on
539 * 528 *
540 * Side Effects: 529 * Side Effects:
541 * - none 530 * - none
542 */ 531 */
543chanuser_t * 532chanuser_t *
544chanuser_find (channel_t *chan, user_t *user) 533chanuser_find (channel_t *c, user_t *user)
545{ 534{
546 node_t *n; 535 node_t *n;
547 chanuser_t *cu; 536 chanuser_t *cu;
548 537
549 if ((!chan) || (!user)) 538 if ((!c) || (!user))
550 return NULL; 539 return NULL;
551 540
552 /* choose shortest list to search -- jilles */ 541 /* choose shortest list to search -- jilles */
553 if (LIST_LENGTH (&user->channels) < LIST_LENGTH (&chan->members)) 542 if (LIST_LENGTH (&user->channels) < LIST_LENGTH (&c->members))
554 { 543 {
555 LIST_FOREACH (n, user->channels.head) 544 LIST_FOREACH (n, user->channels.head)
556 { 545 {
557 cu = (chanuser_t *) n->data; 546 cu = (chanuser_t *) n->data;
558 547
559 if (cu->chan == chan) 548 if (cu->chan == c)
560 return cu; 549 return cu;
561 } 550 }
562 } 551 }
563 else 552 else
564 { 553 {
565 LIST_FOREACH (n, chan->members.head) 554 LIST_FOREACH (n, c->members.head)
566 { 555 {
567 cu = (chanuser_t *) n->data; 556 cu = (chanuser_t *) n->data;
568 557
569 if (cu->user == user) 558 if (cu->user == user)
570 return cu; 559 return cu;
571 } 560 }
572 } 561 }
573 562
574 return NULL; 563 return NULL;
575} 564}
576
577/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
578 * vim:ts=8
579 * vim:sw=8
580 * vim:noexpandtab
581 */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines