1 /* hash.c - IRC network state database
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * x3 is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with srvx; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 #if defined(HAVE_LIBGEOIP)&&defined(HAVE_GEOIP_H)&&defined(HAVE_GEOIPCITY_H)
28 #include <GeoIPCity.h>
38 unsigned int max_clients
, invis_clients
;
39 time_t max_clients_time
;
40 struct userList curr_opers
;
42 static void hash_cleanup(void *extra
);
44 void init_structs(void)
46 channels
= dict_new();
49 userList_init(&curr_opers
);
50 reg_exit_func(hash_cleanup
, NULL
);
53 int userList_contains(struct userList
*list
, struct userNode
*user
)
57 for (ii
= 0; ii
< list
->used
; ++ii
) {
58 if (user
== list
->list
[ii
]) {
65 server_link_func_t
*slf_list
;
66 void **slf_list_extra
;
67 unsigned int slf_size
= 0, slf_used
= 0;
70 reg_server_link_func(server_link_func_t handler
, void *extra
)
72 if (slf_used
== slf_size
) {
75 slf_list
= realloc(slf_list
, slf_size
*sizeof(server_link_func_t
));
76 slf_list_extra
= realloc(slf_list_extra
, slf_size
*sizeof(void*));
79 slf_list
= malloc(slf_size
*sizeof(server_link_func_t
));
80 slf_list_extra
= malloc(slf_size
*sizeof(void*));
83 slf_list
[slf_used
] = handler
;
84 slf_list_extra
[slf_used
++] = extra
;
88 call_server_link_funcs(struct server
*server
)
92 for (i
= 0; i
< slf_used
; ++i
)
94 slf_list
[i
](server
, slf_list_extra
[i
]);
99 GetServerH(const char *name
)
101 return dict_find(servers
, name
, NULL
);
104 sasl_input_func_t
*sif_list
;
105 void **sif_list_extra
;
106 unsigned int sif_size
= 0, sif_used
= 0;
109 reg_sasl_input_func(sasl_input_func_t handler
, void *extra
)
111 if (sif_used
== sif_size
) {
114 sif_list
= realloc(sif_list
, sif_size
*sizeof(new_user_func_t
));
115 sif_list_extra
= realloc(sif_list_extra
, sif_size
*sizeof(void*));
118 sif_list
= malloc(sif_size
*sizeof(new_user_func_t
));
119 sif_list_extra
= malloc(sif_size
*sizeof(void*));
122 sif_list
[sif_used
] = handler
;
123 sif_list_extra
[sif_used
++] = extra
;
127 call_sasl_input_func(struct server
* source
,const char *identifier
, const char *subcmd
, const char *data
, const char *ext
)
131 for (i
= 0; i
< sif_used
; ++i
)
133 sif_list
[i
](source
, identifier
, subcmd
, data
, ext
, sif_list_extra
[i
]);
138 unreg_sasl_input_func(sasl_input_func_t handler
, void *extra
)
141 for (i
=0; i
<sif_used
; i
++) {
142 if (sif_list
[i
] == handler
&& sif_list_extra
[i
] == extra
) break;
144 if (i
== sif_used
) return;
145 memmove(sif_list
+i
, sif_list
+i
+1, (sif_used
-i
-1)*sizeof(sif_list
[0]));
146 memmove(sif_list_extra
+i
, sif_list_extra
+i
+1, (sif_used
-i
-1)*sizeof(sif_list_extra
[0]));
150 new_user_func_t
*nuf_list
;
151 void **nuf_list_extra
;
152 unsigned int nuf_size
= 0, nuf_used
= 0;
155 reg_new_user_func(new_user_func_t handler
, void *extra
)
157 if (nuf_used
== nuf_size
) {
160 nuf_list
= realloc(nuf_list
, nuf_size
*sizeof(new_user_func_t
));
161 nuf_list_extra
= realloc(nuf_list_extra
, nuf_size
*sizeof(void*));
164 nuf_list
= malloc(nuf_size
*sizeof(new_user_func_t
));
165 nuf_list_extra
= malloc(nuf_size
*sizeof(void*));
168 nuf_list
[nuf_used
] = handler
;
169 nuf_list_extra
[nuf_used
++] = extra
;
173 call_new_user_funcs(struct userNode
* user
)
177 for (i
= 0; i
< nuf_used
&& !(user
->dead
); ++i
)
179 nuf_list
[i
](user
, nuf_list_extra
[i
]);
183 static nick_change_func_t
*ncf2_list
;
184 static void **ncf2_list_extra
;
185 static unsigned int ncf2_size
= 0, ncf2_used
= 0;
188 reg_nick_change_func(nick_change_func_t handler
, void *extra
)
190 if (ncf2_used
== ncf2_size
) {
193 ncf2_list
= realloc(ncf2_list
, ncf2_size
*sizeof(nick_change_func_t
));
194 ncf2_list_extra
= realloc(ncf2_list_extra
, ncf2_size
*sizeof(void*));
197 ncf2_list
= malloc(ncf2_size
*sizeof(nick_change_func_t
));
198 ncf2_list_extra
= malloc(ncf2_size
*sizeof(void*));
201 ncf2_list
[ncf2_used
] = handler
;
202 ncf2_list_extra
[ncf2_used
++] = extra
;
206 del_user_func_t
*duf_list
;
207 void **duf_list_extra
;
208 unsigned int duf_size
= 0, duf_used
= 0;
211 reg_del_user_func(del_user_func_t handler
, void *extra
)
213 if (duf_used
== duf_size
) {
216 duf_list
= realloc(duf_list
, duf_size
*sizeof(del_user_func_t
));
217 duf_list_extra
= realloc(duf_list_extra
, duf_size
*sizeof(void*));
220 duf_list
= malloc(duf_size
*sizeof(del_user_func_t
));
221 duf_list_extra
= malloc(duf_size
*sizeof(void*));
224 duf_list
[duf_used
] = handler
;
225 duf_list_extra
[duf_used
++] = extra
;
229 call_del_user_funcs(struct userNode
*user
, struct userNode
*killer
, const char *why
)
233 for (i
= 0; i
< duf_used
; ++i
)
235 duf_list
[i
](user
, killer
, why
, duf_list_extra
[i
]);
240 unreg_del_user_func(del_user_func_t handler
, void *extra
)
243 for (i
=0; i
<duf_used
; i
++) {
244 if (duf_list
[i
] == handler
&& duf_list_extra
[i
] == extra
) break;
246 if (i
== duf_used
) return;
247 memmove(duf_list
+i
, duf_list
+i
+1, (duf_used
-i
-1)*sizeof(duf_list
[0]));
248 memmove(duf_list_extra
+i
, duf_list_extra
+i
+1, (duf_used
-i
-1)*sizeof(duf_list_extra
[0]));
252 /* reintroduces a user after it has been killed. */
254 ReintroduceUser(struct userNode
*user
)
256 struct mod_chanmode change
;
260 mod_chanmode_init(&change
);
262 for (n
= 0; n
< user
->channels
.used
; n
++) {
263 struct modeNode
*mn
= user
->channels
.list
[n
];
264 irc_join(user
, mn
->channel
);
266 change
.args
[0].mode
= mn
->modes
;
267 change
.args
[0].u
.member
= mn
;
268 mod_chanmode_announce(user
, mn
->channel
, &change
);
274 NickChange(struct userNode
* user
, const char *new_nick
, int no_announce
)
279 /* don't do anything if there's no change */
280 old_nick
= user
->nick
;
281 if (!strncmp(new_nick
, old_nick
, NICKLEN
))
284 /* remove old entry from clients dictionary */
285 dict_remove(clients
, old_nick
);
286 #if !defined(WITH_PROTOCOL_P10)
287 /* Remove from uplink's clients dict */
288 dict_remove(user
->uplink
->users
, old_nick
);
291 user
->nick
= strdup(new_nick
);
292 dict_insert(clients
, user
->nick
, user
);
293 #if !defined(WITH_PROTOCOL_P10)
294 dict_insert(user
->uplink
->users
, user
->nick
, user
);
297 /* Make callbacks for nick changes. Do this with new nick in
298 * place because that is slightly more useful.
300 for (nn
=0; (nn
<ncf2_used
) && !user
->dead
; nn
++)
301 ncf2_list
[nn
](user
, old_nick
, ncf2_list_extra
[nn
]);
302 user
->timestamp
= now
;
303 if (IsLocal(user
) && !no_announce
)
304 irc_nick(user
, old_nick
);
309 SVSNickChange(struct userNode
* user
, const char *new_nick
)
314 /* don't do anything if there's no change */
315 old_nick
= user
->nick
;
316 if (!strncmp(new_nick
, old_nick
, NICKLEN
))
319 /* remove old entry from clients dictionary */
320 dict_remove(clients
, old_nick
);
321 #if !defined(WITH_PROTOCOL_P10)
322 /* Remove from uplink's clients dict */
323 dict_remove(user
->uplink
->users
, old_nick
);
326 user
->nick
= strdup(new_nick
);
327 dict_insert(clients
, user
->nick
, user
);
328 #if !defined(WITH_PROTOCOL_P10)
329 dict_insert(user
->uplink
->users
, user
->nick
, user
);
332 /* Make callbacks for nick changes. Do this with new nick in
333 * place because that is slightly more useful.
335 for (nn
=0; (nn
<ncf2_used
) && !user
->dead
; nn
++)
336 ncf2_list
[nn
](user
, old_nick
, ncf2_list_extra
[nn
]);
337 user
->timestamp
= now
;
343 GetUserH(const char *nick
)
345 return dict_find(clients
, nick
, NULL
);
348 static account_func_t account_func
;
351 reg_account_func(account_func_t handler
)
354 log_module(MAIN_LOG
, LOG_WARNING
, "Reregistering ACCOUNT handler.");
356 account_func
= handler
;
360 call_account_func(struct userNode
*user
, const char *stamp
)
362 /* We've received an account stamp for a user; notify
363 NickServ, which registers the sole account_func
364 right now. TODO: This is a bug. This needs to register
365 a proper list not just kill with each call!! -Rubin
367 P10 Protocol violation if (user->modes & FLAGS_STAMPED) here.
370 account_func(user
, stamp
);
372 #ifdef WITH_PROTOCOL_P10
373 /* Mark the user so we don't stamp it again. */
374 user
->modes
|= FLAGS_STAMPED
;
379 StampUser(struct userNode
*user
, const char *stamp
, time_t timestamp
)
381 #ifdef WITH_PROTOCOL_P10
382 /* The P10 protocol says we can't stamp users who already
388 irc_account(user
, stamp
, timestamp
);
389 user
->modes
|= FLAGS_STAMPED
;
393 assign_fakehost(struct userNode
*user
, const char *host
, int announce
)
395 safestrncpy(user
->fakehost
, host
, sizeof(user
->fakehost
));
397 irc_fakehost(user
, host
);
401 set_geoip_info(struct userNode
*user
)
405 /* Need the libs and the headers if this is going to compile properly */
406 #if defined(HAVE_LIBGEOIP)&&defined(HAVE_GEOIP_H)&&defined(HAVE_GEOIPCITY_H)
408 const char *geoip_data_file
= NULL
;
409 const char *geoip_city_file
= NULL
;
411 geoip_data_file
= conf_get_data("services/opserv/geoip_data_file", RECDB_QSTRING
);
412 geoip_city_file
= conf_get_data("services/opserv/geoip_city_data_file", RECDB_QSTRING
);
414 if ((!geoip_data_file
&& !geoip_city_file
))
415 return; /* Admin doesnt want to use geoip functions */
417 if (geoip_data_file
&& !gi
)
418 gi
= GeoIP_open(geoip_data_file
, GEOIP_MEMORY_CACHE
| GEOIP_CHECK_CACHE
);
420 if (geoip_city_file
&& !cgi
)
421 cgi
= GeoIP_open(geoip_city_file
, GEOIP_MEMORY_CACHE
| GEOIP_CHECK_CACHE
);
424 gir
= GeoIP_record_by_name(cgi
, user
->hostname
);
426 user
->country_name
= strdup(gir
->country_name
? gir
->country_name
: "");
427 user
->country_code
= strdup(gir
->country_code
? gir
->country_code
: "");
428 user
->city
= strdup(gir
->city
? gir
->city
: "");
429 user
->region
= strdup(gir
->region
? gir
->region
: "");
430 user
->postal_code
= strdup(gir
->postal_code
? gir
->postal_code
: "");
432 user
->latitude
= gir
->latitude
? gir
->latitude
: 0;
433 user
->longitude
= gir
->longitude
? gir
->longitude
: 0;
434 user
->dma_code
= gir
->dma_code
? gir
->dma_code
: 0;
435 user
->area_code
= gir
->area_code
? gir
->area_code
: 0;
437 GeoIPRecord_delete(gir
);
442 const char *country
= GeoIP_country_name_by_name(gi
, user
->hostname
);
443 user
->country_name
= strdup(country
? country
: "");
451 static new_channel_func_t
*ncf_list
;
452 static void **ncf_list_extra
;
453 static unsigned int ncf_size
= 0, ncf_used
= 0;
456 reg_new_channel_func(new_channel_func_t handler
, void *extra
)
458 if (ncf_used
== ncf_size
) {
461 ncf_list
= realloc(ncf_list
, ncf_size
*sizeof(ncf_list
[0]));
462 ncf_list_extra
= realloc(ncf_list_extra
, ncf_size
*sizeof(void*));
465 ncf_list
= malloc(ncf_size
*sizeof(ncf_list
[0]));
466 ncf_list_extra
= malloc(ncf_size
*sizeof(void*));
469 ncf_list
[ncf_used
] = handler
;
470 ncf_list_extra
[ncf_used
++] = extra
;
473 static join_func_t
*jf_list
;
474 static void **jf_list_extra
;
475 static unsigned int jf_size
= 0, jf_used
= 0;
478 reg_join_func(join_func_t handler
, void *extra
)
480 if (jf_used
== jf_size
) {
483 jf_list
= realloc(jf_list
, jf_size
*sizeof(join_func_t
));
484 jf_list_extra
= realloc(jf_list_extra
, jf_size
*sizeof(void*));
487 jf_list
= malloc(jf_size
*sizeof(join_func_t
));
488 jf_list_extra
= malloc(jf_size
*sizeof(void*));
491 jf_list
[jf_used
] = handler
;
492 jf_list_extra
[jf_used
++] = extra
;
498 wipeout_channel(struct chanNode
*cNode
, time_t new_time
, char **modes
, unsigned int modec
) {
499 unsigned int orig_limit
;
500 chan_mode_t orig_modes
;
501 char orig_key
[KEYLEN
+1];
502 char orig_apass
[KEYLEN
+1];
503 char orig_upass
[KEYLEN
+1];
504 unsigned int nn
, argc
;
507 cNode
->topic
[0] = '\0';
508 cNode
->topic_nick
[0] = '\0';
509 cNode
->topic_time
= 0;
511 /* remember the old modes, and update them with the new */
512 orig_modes
= cNode
->modes
;
513 orig_limit
= cNode
->limit
;
514 strcpy(orig_key
, cNode
->key
);
515 strcpy(orig_upass
, cNode
->upass
);
516 strcpy(orig_apass
, cNode
->apass
);
518 mod_chanmode(NULL
, cNode
, modes
, modec
, 0);
519 cNode
->timestamp
= new_time
;
521 /* remove our old ban list, replace it with the new one */
522 for (nn
=0; nn
<cNode
->banlist
.used
; nn
++)
523 free(cNode
->banlist
.list
[nn
]);
524 cNode
->banlist
.used
= 0;
526 /* remove our old exe,[t list, replace it with the new one */
527 for (nn
=0; nn
<cNode
->exemptlist
.used
; nn
++)
528 free(cNode
->exemptlist
.list
[nn
]);
529 cNode
->exemptlist
.used
= 0;
531 /* deop anybody in the channel now, but count services to reop */
532 for (nn
=argc
=0; nn
<cNode
->members
.used
; nn
++) {
533 struct modeNode
*mn
= cNode
->members
.list
[nn
];
534 if ((mn
->modes
& MODE_CHANOP
) && IsService(mn
->user
) && IsLocal(mn
->user
))
539 struct mod_chanmode
*change
;
541 change
= mod_chanmode_alloc(argc
);
542 change
->modes_clear
= 0;
543 change
->modes_set
= orig_modes
;
544 change
->new_limit
= orig_limit
;
545 strcpy(change
->new_key
, orig_key
);
546 strcpy(change
->new_upass
, orig_upass
);
547 strcpy(change
->new_apass
, orig_apass
);
548 for (nn
= argc
= 0; nn
< cNode
->members
.used
; ++nn
) {
549 struct modeNode
*mn
= cNode
->members
.list
[nn
];
550 if ((mn
->modes
& MODE_CHANOP
) && IsService(mn
->user
) && IsLocal(mn
->user
)) {
551 change
->args
[argc
].mode
= MODE_CHANOP
;
552 change
->args
[argc
].u
.member
= mn
;
556 assert(argc
== change
->argc
);
557 change
->args
[0].u
.member
->modes
&= ~MODE_CHANOP
;
558 mod_chanmode_announce(change
->args
[0].u
.member
->user
, cNode
, change
);
559 mod_chanmode_free(change
);
564 AddChannel(const char *name
, time_t time_
, const char *modes
, char *banlist
, char *exemptlist
)
566 struct chanNode
*cNode
;
567 char new_modes
[MAXLEN
], *argv
[MAXNUMPARAMS
];
570 if (!IsChannelName(name
)) {
571 log_module(MAIN_LOG
, LOG_ERROR
, "Somebody asked to add channel '%s', which isn't a channel name!", name
);
577 safestrncpy(new_modes
, modes
, sizeof(new_modes
));
578 nn
= split_line(new_modes
, 0, ArrayLength(argv
), argv
);
579 if (!(cNode
= GetChannel(name
))) {
580 cNode
= calloc(1, sizeof(*cNode
) + strlen(name
));
581 strcpy(cNode
->name
, name
);
582 banList_init(&cNode
->banlist
);
583 exemptList_init(&cNode
->exemptlist
);
584 modeList_init(&cNode
->members
);
585 mod_chanmode(NULL
, cNode
, argv
, nn
, MCP_FROM_SERVER
);
586 dict_insert(channels
, cNode
->name
, cNode
);
587 cNode
->timestamp
= time_
;
589 } else if (cNode
->timestamp
> time_
) {
590 wipeout_channel(cNode
, time_
, argv
, nn
);
592 } else if (cNode
->timestamp
== time_
) {
593 mod_chanmode(NULL
, cNode
, argv
, nn
, MCP_FROM_SERVER
);
599 /* rel_age is the relative ages of our channel data versus what is
600 * in a BURST command. 1 means ours is younger, 0 means both are
601 * the same age, -1 means ours is older. */
603 /* if it's a new or updated channel, make callbacks */
605 for (nn
=0; nn
<ncf_used
; nn
++)
606 ncf_list
[nn
](cNode
, ncf_list_extra
[nn
]);
608 /* go through list of bans and add each one */
609 if (banlist
&& (rel_age
>= 0)) {
610 for (nn
=0; banlist
[nn
];) {
611 char *ban
= banlist
+ nn
;
613 while (banlist
[nn
] != ' ' && banlist
[nn
])
615 while (banlist
[nn
] == ' ')
617 bn
= calloc(1, sizeof(*bn
));
618 safestrncpy(bn
->ban
, ban
, sizeof(bn
->ban
));
619 safestrncpy(bn
->who
, "<unknown>", sizeof(bn
->who
));
621 banList_append(&cNode
->banlist
, bn
);
625 /* go through list of exempts and add each one */
626 if (exemptlist
&& (rel_age
>= 0)) {
627 for (nn
=0; exemptlist
[nn
];) {
628 char *exempt
= exemptlist
+ nn
;
629 struct exemptNode
*en
;
630 while (exemptlist
[nn
] != ' ' && exemptlist
[nn
])
632 while (exemptlist
[nn
] == ' ')
633 exemptlist
[nn
++] = 0;
634 en
= calloc(1, sizeof(*en
));
635 safestrncpy(en
->exempt
, exempt
, sizeof(en
->exempt
));
636 safestrncpy(en
->who
, "<unknown>", sizeof(en
->who
));
638 exemptList_append(&cNode
->exemptlist
, en
);
645 static del_channel_func_t
*dcf_list
;
646 static void **dcf_list_extra
;
647 static unsigned int dcf_size
= 0, dcf_used
= 0;
650 reg_del_channel_func(del_channel_func_t handler
, void *extra
)
652 if (dcf_used
== dcf_size
) {
655 dcf_list
= realloc(dcf_list
, dcf_size
*sizeof(dcf_list
[0]));
656 dcf_list_extra
= realloc(dcf_list_extra
, dcf_size
*sizeof(void*));
659 dcf_list
= malloc(dcf_size
*sizeof(dcf_list
[0]));
660 dcf_list_extra
= malloc(dcf_size
*sizeof(dcf_list_extra
[0]));
663 dcf_list
[dcf_used
] = handler
;
664 dcf_list_extra
[dcf_used
++] = extra
;
668 DelChannel(struct chanNode
*channel
)
673 dict_remove(channels
, channel
->name
);
675 if (channel
->members
.used
|| channel
->locks
) {
676 log_module(MAIN_LOG
, LOG_ERROR
, "Warning: deleting channel %s with %d users and %d locks remaining.", channel
->name
, channel
->members
.used
, channel
->locks
);
679 /* go through all channel members and delete them from the channel */
680 for (n
=channel
->members
.used
; n
>0; )
681 DelChannelUser(channel
->members
.list
[--n
]->user
, channel
, NULL
, 1);
683 /* delete all channel bans */
684 for (n
=channel
->banlist
.used
; n
>0; )
685 free(channel
->banlist
.list
[--n
]);
686 channel
->banlist
.used
= 0;
688 /* delete all channel exempts */
689 for (n
=channel
->exemptlist
.used
; n
>0; )
690 free(channel
->exemptlist
.list
[--n
]);
691 channel
->exemptlist
.used
= 0;
693 for (n
=0; n
<dcf_used
; n
++)
694 dcf_list
[n
](channel
, dcf_list_extra
[n
]);
696 modeList_clean(&channel
->members
);
697 banList_clean(&channel
->banlist
);
698 exemptList_clean(&channel
->exemptlist
);
703 AddChannelUser(struct userNode
*user
, struct chanNode
* channel
)
705 struct modeNode
*mNode
;
708 mNode
= GetUserMode(channel
, user
);
712 mNode
= malloc(sizeof(*mNode
));
714 /* set up modeNode */
715 mNode
->channel
= channel
;
719 mNode
->idle_since
= now
;
721 /* Add modeNode to channel and to user.
722 * We have to do this before calling join funcs in case the
723 * modeNode is manipulated (e.g. chanserv ops the user).
725 modeList_append(&channel
->members
, mNode
);
726 modeList_append(&user
->channels
, mNode
);
728 if (channel
->members
.used
== 1
729 && !(channel
->modes
& MODE_REGISTERED
)
730 && !(channel
->modes
& MODE_APASS
)) {
731 mNode
->modes
|= MODE_CHANOP
;
732 log_module(MAIN_LOG
, LOG_DEBUG
, "setting op");
736 irc_join(user
, channel
);
739 for (n
=0; (n
<jf_used
) && !user
->dead
; n
++) {
740 /* Callbacks return true if they kick or kill the user,
741 * and we can continue without removing mNode. */
742 if (jf_list
[n
](mNode
, jf_list_extra
[n
]))
749 static part_func_t
*pf_list
;
750 static void **pf_list_extra
;
751 static unsigned int pf_size
= 0, pf_used
= 0;
754 reg_part_func(part_func_t handler
, void *extra
)
756 if (pf_used
== pf_size
) {
759 pf_list
= realloc(pf_list
, pf_size
*sizeof(part_func_t
));
760 pf_list_extra
= realloc(pf_list_extra
, pf_size
*sizeof(void*));
763 pf_list
= malloc(pf_size
*sizeof(part_func_t
));
764 pf_list_extra
= malloc(pf_size
*sizeof(void*));
767 pf_list
[pf_used
] = handler
;
768 pf_list_extra
[pf_used
++] = extra
;
772 unreg_part_func(part_func_t handler
, void *extra
)
775 for (i
=0; i
<pf_used
; i
++)
776 if (pf_list
[i
] == handler
&& pf_list_extra
[i
] == extra
)
780 memmove(pf_list
+i
, pf_list
+i
+1, (pf_used
-i
-1)*sizeof(pf_list
[0]));
781 memmove(pf_list_extra
+i
, pf_list_extra
+i
+1, (pf_used
-i
-1)*sizeof(pf_list_extra
[0]));
786 LockChannel(struct chanNode
* channel
)
792 UnlockChannel(struct chanNode
*channel
)
794 assert(channel
->locks
> 0);
795 if (!--channel
->locks
&& !channel
->members
.used
)
800 DelChannelUser(struct userNode
* user
, struct chanNode
* channel
, const char *reason
, int deleting
)
802 struct modeNode
* mNode
;
805 if (IsLocal(user
) && reason
)
806 irc_part(user
, channel
, reason
);
808 mNode
= GetUserMode(channel
, user
);
810 /* Sometimes we get a PART when the user has been KICKed.
811 * In this case, we get no usermode, and should not try to free it.
816 /* remove modeNode from channel and user */
817 modeList_remove(&channel
->members
, mNode
);
818 modeList_remove(&user
->channels
, mNode
);
821 for (n
=0; n
<pf_used
; n
++)
822 pf_list
[n
](mNode
, reason
, pf_list_extra
[n
]);
827 /* A single check for APASS only should be enough here */
828 if (!deleting
&& !channel
->members
.used
&& !channel
->locks
829 && !(channel
->modes
& MODE_REGISTERED
) && !(channel
->modes
& MODE_APASS
))
833 static kick_func_t
*kf_list
;
834 static void **kf_list_extra
;
835 static unsigned int kf_size
= 0, kf_used
= 0;
838 KickChannelUser(struct userNode
* target
, struct chanNode
* channel
, struct userNode
*kicker
, const char *why
)
842 if (!target
|| !channel
|| IsService(target
) || !GetUserMode(channel
, target
))
845 /* This may break things, but lets see.. -Rubin */
846 for (n
=0; n
<kf_used
; n
++)
847 kf_list
[n
](kicker
, target
, channel
, kf_list_extra
[n
]);
849 /* don't remove them from the channel, since the server will send a PART */
850 irc_kick(kicker
, target
, channel
, why
);
854 /* NULL reason because we don't want a PART message to be
855 sent by DelChannelUser. */
856 DelChannelUser(target
, channel
, NULL
, 0);
861 reg_kick_func(kick_func_t handler
, void *extra
)
863 if (kf_used
== kf_size
) {
866 kf_list
= realloc(kf_list
, kf_size
*sizeof(kick_func_t
));
867 kf_list_extra
= realloc(kf_list_extra
, kf_size
*sizeof(void*));
870 kf_list
= malloc(kf_size
*sizeof(kick_func_t
));
871 kf_list_extra
= malloc(kf_size
*sizeof(void*));
874 kf_list
[kf_used
] = handler
;
875 kf_list_extra
[kf_used
++] = extra
;
879 ChannelUserKicked(struct userNode
* kicker
, struct userNode
* victim
, struct chanNode
* channel
)
884 if (!victim
|| !channel
|| !GetUserMode(channel
, victim
))
887 /* Update the kicker's idle time (kicker may be null if it was a server) */
888 if (kicker
&& (mn
= GetUserMode(channel
, kicker
)))
889 mn
->idle_since
= now
;
891 for (n
=0; n
<kf_used
; n
++)
892 kf_list
[n
](kicker
, victim
, channel
, kf_list_extra
[n
]);
894 DelChannelUser(victim
, channel
, 0, 0);
897 irc_part(victim
, channel
, NULL
);
900 int ChannelBanExists(struct chanNode
*channel
, const char *ban
)
904 for (n
= 0; n
< channel
->banlist
.used
; n
++)
905 if (match_ircglobs(channel
->banlist
.list
[n
]->ban
, ban
))
910 int ChannelExemptExists(struct chanNode
*channel
, const char *exempt
)
914 for (n
= 0; n
< channel
->exemptlist
.used
; n
++)
915 if (match_ircglobs(channel
->exemptlist
.list
[n
]->exempt
, exempt
))
920 static topic_func_t
*tf_list
;
921 static void **tf_list_extra
;
922 static unsigned int tf_size
= 0, tf_used
= 0;
925 reg_topic_func(topic_func_t handler
, void *extra
)
927 if (tf_used
== tf_size
) {
930 tf_list
= realloc(tf_list
, tf_size
*sizeof(topic_func_t
));
931 tf_list_extra
= realloc(tf_list_extra
, tf_size
*sizeof(void*));
934 tf_list
= malloc(tf_size
*sizeof(topic_func_t
));
935 tf_list_extra
= malloc(tf_size
*sizeof(void*));
938 tf_list
[tf_used
] = handler
;
939 tf_list_extra
[tf_used
++] = extra
;
943 SetChannelTopic(struct chanNode
*channel
, struct userNode
*service
, struct userNode
*user
, const char *topic
, int announce
)
947 char old_topic
[TOPICLEN
+1];
949 safestrncpy(old_topic
, channel
->topic
, sizeof(old_topic
));
950 safestrncpy(channel
->topic
, topic
, sizeof(channel
->topic
));
951 channel
->topic_time
= now
;
954 safestrncpy(channel
->topic_nick
, user
->nick
, sizeof(channel
->topic_nick
));
956 /* Update the setter's idle time */
957 if ((mn
= GetUserMode(channel
, user
)))
958 mn
->idle_since
= now
;
962 /* We don't really care if a local user messes with the topic,
963 * so don't call the tf_list functions. */
964 irc_topic(service
, user
, channel
, topic
);
966 for (n
=0; n
<tf_used
; n
++)
967 /* A topic change handler can return non-zero to indicate
968 * that it has reverted the topic change, and that further
969 * hooks should not be called.
971 if (tf_list
[n
](user
, channel
, old_topic
, tf_list_extra
[n
]))
977 GetChannel(const char *name
)
979 return dict_find(channels
, name
, NULL
);
983 GetUserMode(struct chanNode
*channel
, struct userNode
*user
)
986 struct modeNode
*mn
= NULL
;
989 verify(channel
->members
.list
);
991 verify(user
->channels
.list
);
992 if (channel
->members
.used
< user
->channels
.used
) {
993 for (n
=0; n
<channel
->members
.used
; n
++) {
994 verify(channel
->members
.list
[n
]);
995 if (user
== channel
->members
.list
[n
]->user
) {
996 mn
= channel
->members
.list
[n
];
1001 for (n
=0; n
<user
->channels
.used
; n
++) {
1002 verify(user
->channels
.list
[n
]);
1003 if (channel
== user
->channels
.list
[n
]->channel
) {
1004 mn
= user
->channels
.list
[n
];
1012 struct userNode
*IsInChannel(struct chanNode
*channel
, struct userNode
*user
)
1017 verify(channel
->members
.list
);
1019 verify(user
->channels
.list
);
1020 if (channel
->members
.used
< user
->channels
.used
) {
1021 for (n
=0; n
<channel
->members
.used
; n
++) {
1022 verify(channel
->members
.list
[n
]);
1023 if (user
== channel
->members
.list
[n
]->user
) {
1028 for (n
=0; n
<user
->channels
.used
; n
++) {
1029 verify(user
->channels
.list
[n
]);
1030 if (channel
== user
->channels
.list
[n
]->channel
) {
1038 DEFINE_LIST(userList
, struct userNode
*)
1039 DEFINE_LIST(modeList
, struct modeNode
*)
1040 DEFINE_LIST(banList
, struct banNode
*)
1041 DEFINE_LIST(exemptList
, struct exemptNode
*)
1042 DEFINE_LIST(channelList
, struct chanNode
*)
1043 DEFINE_LIST(serverList
, struct server
*)
1046 hash_cleanup(UNUSED_ARG(void *extra
))
1048 dict_iterator_t it
, next
;
1050 DelServer(self
, 0, NULL
);
1051 for (it
= dict_first(channels
); it
; it
= next
) {
1052 next
= iter_next(it
);
1053 DelChannel(iter_data(it
));
1055 dict_delete(channels
);
1056 dict_delete(clients
);
1057 dict_delete(servers
);
1058 userList_clean(&curr_opers
);
1061 free(slf_list_extra
);
1063 free(nuf_list_extra
);
1065 free(ncf2_list_extra
);
1067 free(duf_list_extra
);
1069 free(ncf_list_extra
);
1071 free(jf_list_extra
);
1073 free(dcf_list_extra
);
1075 free(pf_list_extra
);
1077 free(kf_list_extra
);
1079 free(tf_list_extra
);