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 | |
8 | static char const rcsid[] = "$Id: channels.C,v 1.3 2007/07/21 13:23:21 pippijn Exp $"; |
8 | static 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 | |
13 | dictionary_tree_t *chanlist; |
13 | dictionary_tree_t *chanlist; |
14 | |
14 | channel_t::callbacks channel_t::callback; |
15 | static BlockHeap *chan_heap; |
15 | chanuser_t::callbacks chanuser_t::callback; |
16 | static BlockHeap *chanuser_heap; |
|
|
17 | static 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 | */ |
33 | void |
31 | void |
34 | init_channels (void) |
32 | init_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 | */ |
71 | channel_t * |
65 | channel_t * |
72 | channel_add (const char *name, unsigned int ts, server_t *creator) |
66 | channel_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 | */ |
203 | channel_t * |
197 | channel_t * |
204 | channel_find (const char *name) |
198 | channel_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 | */ |
226 | chanban_t * |
220 | chanban_t * |
227 | chanban_add (channel_t *chan, const char *mask, int type) |
221 | chanban_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 | */ |
316 | chanban_t * |
310 | chanban_t * |
317 | chanban_find (channel_t *chan, const char *mask, int type) |
311 | chanban_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 | */ |
348 | void |
342 | void |
349 | chanban_clear (channel_t *chan) |
343 | chanban_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 | */ |
391 | chanuser_t * |
385 | chanuser_t * |
392 | chanuser_add (channel_t *chan, const char *nick) |
386 | chanuser_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 | */ |
482 | void |
473 | void |
483 | chanuser_delete (channel_t *chan, user_t *user) |
474 | chanuser_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 | */ |
543 | chanuser_t * |
532 | chanuser_t * |
544 | chanuser_find (channel_t *chan, user_t *user) |
533 | chanuser_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 | */ |
|
|