X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/55342ce8a8e0e89892433948d7bb660682d13804..1ef37f9e521eaa2673d792badff62c25681a009e:/src/hash.c?ds=sidebyside diff --git a/src/hash.c b/src/hash.c index 41d75e1..1adfeca 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,11 +1,11 @@ /* hash.c - IRC network state database * Copyright 2000-2004 srvx Development Team * - * This file is part of srvx. + * This file is part of x3. * - * srvx is free software; you can redistribute it and/or modify + * x3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -23,6 +23,14 @@ #include "hash.h" #include "log.h" +#if defined(HAVE_LIBGEOIP)&&defined(HAVE_GEOIP_H)&&defined(HAVE_GEOIPCITY_H) +#include +#include + +GeoIP * gi = NULL; +GeoIP * cgi = NULL; +#endif + struct server *self; dict_t channels; dict_t clients; @@ -31,7 +39,7 @@ unsigned int max_clients, invis_clients; time_t max_clients_time; struct userList curr_opers; -static void hash_cleanup(void); +static void hash_cleanup(void *extra); void init_structs(void) { @@ -39,25 +47,52 @@ void init_structs(void) clients = dict_new(); servers = dict_new(); userList_init(&curr_opers); - reg_exit_func(hash_cleanup); + reg_exit_func(hash_cleanup, NULL); +} + +int userList_contains(struct userList *list, struct userNode *user) +{ + unsigned int ii; + + for (ii = 0; ii < list->used; ++ii) { + if (user == list->list[ii]) { + return 1; + } + } + return 0; } server_link_func_t *slf_list; +void **slf_list_extra; unsigned int slf_size = 0, slf_used = 0; void -reg_server_link_func(server_link_func_t handler) +reg_server_link_func(server_link_func_t handler, void *extra) { if (slf_used == slf_size) { - if (slf_size) { - slf_size <<= 1; - slf_list = realloc(slf_list, slf_size*sizeof(server_link_func_t)); - } else { - slf_size = 8; - slf_list = malloc(slf_size*sizeof(server_link_func_t)); - } + if (slf_size) { + slf_size <<= 1; + slf_list = realloc(slf_list, slf_size*sizeof(server_link_func_t)); + slf_list_extra = realloc(slf_list_extra, slf_size*sizeof(void*)); + } else { + slf_size = 8; + slf_list = malloc(slf_size*sizeof(server_link_func_t)); + slf_list_extra = malloc(slf_size*sizeof(void*)); + } + } + slf_list[slf_used] = handler; + slf_list_extra[slf_used++] = extra; +} + +void +call_server_link_funcs(struct server *server) +{ + unsigned int i; + + for (i = 0; i < slf_used; ++i) + { + slf_list[i](server, slf_list_extra[i]); } - slf_list[slf_used++] = handler; } struct server* @@ -66,70 +101,151 @@ GetServerH(const char *name) return dict_find(servers, name, NULL); } +sasl_input_func_t *sif_list; +void **sif_list_extra; +unsigned int sif_size = 0, sif_used = 0; + +void +reg_sasl_input_func(sasl_input_func_t handler, void *extra) +{ + if (sif_used == sif_size) { + if (sif_size) { + sif_size <<= 1; + sif_list = realloc(sif_list, sif_size*sizeof(new_user_func_t)); + sif_list_extra = realloc(sif_list_extra, sif_size*sizeof(void*)); + } else { + sif_size = 8; + sif_list = malloc(sif_size*sizeof(new_user_func_t)); + sif_list_extra = malloc(sif_size*sizeof(void*)); + } + } + sif_list[sif_used] = handler; + sif_list_extra[sif_used++] = extra; +} + +void +call_sasl_input_func(struct server* source ,const char *identifier, const char *subcmd, const char *data, const char *ext) +{ + unsigned int i; + + for (i = 0; i < sif_used; ++i) + { + sif_list[i](source, identifier, subcmd, data, ext, sif_list_extra[i]); + } +} + +void +unreg_sasl_input_func(sasl_input_func_t handler, void *extra) +{ + unsigned int i; + for (i=0; idead); ++i) + { + nuf_list[i](user, nuf_list_extra[i]); } - nuf_list[nuf_used++] = handler; } static nick_change_func_t *ncf2_list; +static void **ncf2_list_extra; static unsigned int ncf2_size = 0, ncf2_used = 0; void -reg_nick_change_func(nick_change_func_t handler) +reg_nick_change_func(nick_change_func_t handler, void *extra) { if (ncf2_used == ncf2_size) { if (ncf2_size) { ncf2_size <<= 1; ncf2_list = realloc(ncf2_list, ncf2_size*sizeof(nick_change_func_t)); + ncf2_list_extra = realloc(ncf2_list_extra, ncf2_size*sizeof(void*)); } else { ncf2_size = 8; ncf2_list = malloc(ncf2_size*sizeof(nick_change_func_t)); + ncf2_list_extra = malloc(ncf2_size*sizeof(void*)); } } - ncf2_list[ncf2_used++] = handler; + ncf2_list[ncf2_used] = handler; + ncf2_list_extra[ncf2_used++] = extra; } del_user_func_t *duf_list; +void **duf_list_extra; unsigned int duf_size = 0, duf_used = 0; void -reg_del_user_func(del_user_func_t handler) +reg_del_user_func(del_user_func_t handler, void *extra) { if (duf_used == duf_size) { - if (duf_size) { - duf_size <<= 1; - duf_list = realloc(duf_list, duf_size*sizeof(del_user_func_t)); - } else { - duf_size = 8; - duf_list = malloc(duf_size*sizeof(del_user_func_t)); - } + if (duf_size) { + duf_size <<= 1; + duf_list = realloc(duf_list, duf_size*sizeof(del_user_func_t)); + duf_list_extra = realloc(duf_list_extra, duf_size*sizeof(void*)); + } else { + duf_size = 8; + duf_list = malloc(duf_size*sizeof(del_user_func_t)); + duf_list_extra = malloc(duf_size*sizeof(void*)); + } } - duf_list[duf_used++] = handler; + duf_list[duf_used] = handler; + duf_list_extra[duf_used++] = extra; } void -unreg_del_user_func(del_user_func_t handler) +call_del_user_funcs(struct userNode *user, struct userNode *killer, const char *why) +{ + unsigned int i; + + for (i = 0; i < duf_used; ++i) + { + duf_list[i](user, killer, why, duf_list_extra[i]); + } +} + +void +unreg_del_user_func(del_user_func_t handler, void *extra) { unsigned int i; for (i=0; ichannel); if (mn->modes) { change.args[0].mode = mn->modes; - change.args[0].member = mn; + change.args[0].u.member = mn; mod_chanmode_announce(user, mn->channel, &change); } } @@ -181,14 +297,48 @@ NickChange(struct userNode* user, const char *new_nick, int no_announce) /* Make callbacks for nick changes. Do this with new nick in * place because that is slightly more useful. */ - for (nn=0; nndead; nn++) + ncf2_list[nn](user, old_nick, ncf2_list_extra[nn]); user->timestamp = now; if (IsLocal(user) && !no_announce) irc_nick(user, old_nick); free(old_nick); } +void +SVSNickChange(struct userNode* user, const char *new_nick) +{ + char *old_nick; + unsigned int nn; + + /* don't do anything if there's no change */ + old_nick = user->nick; + if (!strncmp(new_nick, old_nick, NICKLEN)) + return; + + /* remove old entry from clients dictionary */ + dict_remove(clients, old_nick); +#if !defined(WITH_PROTOCOL_P10) + /* Remove from uplink's clients dict */ + dict_remove(user->uplink->users, old_nick); +#endif + /* and reinsert */ + user->nick = strdup(new_nick); + dict_insert(clients, user->nick, user); +#if !defined(WITH_PROTOCOL_P10) + dict_insert(user->uplink->users, user->nick, user); +#endif + + /* Make callbacks for nick changes. Do this with new nick in + * place because that is slightly more useful. + */ + for (nn=0; (nndead; nn++) + ncf2_list[nn](user, old_nick, ncf2_list_extra[nn]); + user->timestamp = now; + + free(old_nick); +} + struct userNode * GetUserH(const char *nick) { @@ -211,7 +361,8 @@ call_account_func(struct userNode *user, const char *stamp) { /* We've received an account stamp for a user; notify NickServ, which registers the sole account_func - right now. + right now. TODO: This is a bug. This needs to register + a proper list not just kill with each call!! -Rubin P10 Protocol violation if (user->modes & FLAGS_STAMPED) here. */ @@ -225,7 +376,7 @@ call_account_func(struct userNode *user, const char *stamp) } void -StampUser(struct userNode *user, const char *stamp) +StampUser(struct userNode *user, const char *stamp, time_t timestamp) { #ifdef WITH_PROTOCOL_P10 /* The P10 protocol says we can't stamp users who already @@ -234,7 +385,7 @@ StampUser(struct userNode *user, const char *stamp) return; #endif - irc_account(user, stamp); + irc_account(user, stamp, timestamp); user->modes |= FLAGS_STAMPED; } @@ -246,40 +397,99 @@ assign_fakehost(struct userNode *user, const char *host, int announce) irc_fakehost(user, host); } +void +set_geoip_info(struct userNode *user) +{ + if(IsLocal(user)) + return; +/* Need the libs and the headers if this is going to compile properly */ +#if defined(HAVE_LIBGEOIP)&&defined(HAVE_GEOIP_H)&&defined(HAVE_GEOIPCITY_H) + GeoIPRecord * gir; + const char *geoip_data_file = NULL; + const char *geoip_city_file = NULL; + + geoip_data_file = conf_get_data("services/opserv/geoip_data_file", RECDB_QSTRING); + geoip_city_file = conf_get_data("services/opserv/geoip_city_data_file", RECDB_QSTRING); + + if ((!geoip_data_file && !geoip_city_file)) + return; /* Admin doesnt want to use geoip functions */ + + if (geoip_data_file && !gi) + gi = GeoIP_open(geoip_data_file, GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE); + + if (geoip_city_file && !cgi) + cgi = GeoIP_open(geoip_city_file, GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE); + + if (cgi) { + gir = GeoIP_record_by_name(cgi, user->hostname); + if (gir) { + user->country_name = strdup(gir->country_name ? gir->country_name : ""); + user->country_code = strdup(gir->country_code ? gir->country_code : ""); + user->city = strdup(gir->city ? gir->city : ""); + user->region = strdup(gir->region ? gir->region : ""); + user->postal_code = strdup(gir->postal_code ? gir->postal_code : ""); + + user->latitude = gir->latitude ? gir->latitude : 0; + user->longitude = gir->longitude ? gir->longitude : 0; + user->dma_code = gir->dma_code ? gir->dma_code : 0; + user->area_code = gir->area_code ? gir->area_code : 0; + + GeoIPRecord_delete(gir); + } + + return; + } else if (gi) { + const char *country = GeoIP_country_name_by_name(gi, user->hostname); + user->country_name = strdup(country ? country : ""); + return; + } + + return; +#endif +} + static new_channel_func_t *ncf_list; +static void **ncf_list_extra; static unsigned int ncf_size = 0, ncf_used = 0; void -reg_new_channel_func(new_channel_func_t handler) +reg_new_channel_func(new_channel_func_t handler, void *extra) { if (ncf_used == ncf_size) { if (ncf_size) { ncf_size <<= 1; ncf_list = realloc(ncf_list, ncf_size*sizeof(ncf_list[0])); + ncf_list_extra = realloc(ncf_list_extra, ncf_size*sizeof(void*)); } else { ncf_size = 8; ncf_list = malloc(ncf_size*sizeof(ncf_list[0])); + ncf_list_extra = malloc(ncf_size*sizeof(void*)); } } - ncf_list[ncf_used++] = handler; + ncf_list[ncf_used] = handler; + ncf_list_extra[ncf_used++] = extra; } static join_func_t *jf_list; +static void **jf_list_extra; static unsigned int jf_size = 0, jf_used = 0; void -reg_join_func(join_func_t handler) +reg_join_func(join_func_t handler, void *extra) { if (jf_used == jf_size) { if (jf_size) { jf_size <<= 1; jf_list = realloc(jf_list, jf_size*sizeof(join_func_t)); + jf_list_extra = realloc(jf_list_extra, jf_size*sizeof(void*)); } else { jf_size = 8; jf_list = malloc(jf_size*sizeof(join_func_t)); + jf_list_extra = malloc(jf_size*sizeof(void*)); } } - jf_list[jf_used++] = handler; + jf_list[jf_used] = handler; + jf_list_extra[jf_used++] = extra; } int rel_age; @@ -289,6 +499,8 @@ wipeout_channel(struct chanNode *cNode, time_t new_time, char **modes, unsigned unsigned int orig_limit; chan_mode_t orig_modes; char orig_key[KEYLEN+1]; + char orig_apass[KEYLEN+1]; + char orig_upass[KEYLEN+1]; unsigned int nn, argc; /* nuke old topic */ @@ -300,6 +512,8 @@ wipeout_channel(struct chanNode *cNode, time_t new_time, char **modes, unsigned orig_modes = cNode->modes; orig_limit = cNode->limit; strcpy(orig_key, cNode->key); + strcpy(orig_upass, cNode->upass); + strcpy(orig_apass, cNode->apass); cNode->modes = 0; mod_chanmode(NULL, cNode, modes, modec, 0); cNode->timestamp = new_time; @@ -309,6 +523,11 @@ wipeout_channel(struct chanNode *cNode, time_t new_time, char **modes, unsigned free(cNode->banlist.list[nn]); cNode->banlist.used = 0; + /* remove our old exe,[t list, replace it with the new one */ + for (nn=0; nnexemptlist.used; nn++) + free(cNode->exemptlist.list[nn]); + cNode->exemptlist.used = 0; + /* deop anybody in the channel now, but count services to reop */ for (nn=argc=0; nnmembers.used; nn++) { struct modeNode *mn = cNode->members.list[nn]; @@ -324,23 +543,25 @@ wipeout_channel(struct chanNode *cNode, time_t new_time, char **modes, unsigned change->modes_set = orig_modes; change->new_limit = orig_limit; strcpy(change->new_key, orig_key); + strcpy(change->new_upass, orig_upass); + strcpy(change->new_apass, orig_apass); for (nn = argc = 0; nn < cNode->members.used; ++nn) { struct modeNode *mn = cNode->members.list[nn]; if ((mn->modes & MODE_CHANOP) && IsService(mn->user) && IsLocal(mn->user)) { change->args[argc].mode = MODE_CHANOP; - change->args[argc].member = mn; + change->args[argc].u.member = mn; argc++; } } assert(argc == change->argc); - change->args[0].member->modes &= ~MODE_CHANOP; - mod_chanmode_announce(change->args[0].member->user, cNode, change); + change->args[0].u.member->modes &= ~MODE_CHANOP; + mod_chanmode_announce(change->args[0].u.member->user, cNode, change); mod_chanmode_free(change); } } struct chanNode * -AddChannel(const char *name, time_t time_, const char *modes, char *banlist) +AddChannel(const char *name, time_t time_, const char *modes, char *banlist, char *exemptlist) { struct chanNode *cNode; char new_modes[MAXLEN], *argv[MAXNUMPARAMS]; @@ -359,8 +580,9 @@ AddChannel(const char *name, time_t time_, const char *modes, char *banlist) cNode = calloc(1, sizeof(*cNode) + strlen(name)); strcpy(cNode->name, name); banList_init(&cNode->banlist); + exemptList_init(&cNode->exemptlist); modeList_init(&cNode->members); - mod_chanmode(NULL, cNode, argv, nn, 0); + mod_chanmode(NULL, cNode, argv, nn, MCP_FROM_SERVER); dict_insert(channels, cNode->name, cNode); cNode->timestamp = time_; rel_age = 1; @@ -368,7 +590,7 @@ AddChannel(const char *name, time_t time_, const char *modes, char *banlist) wipeout_channel(cNode, time_, argv, nn); rel_age = 1; } else if (cNode->timestamp == time_) { - mod_chanmode(NULL, cNode, argv, nn, 0); + mod_chanmode(NULL, cNode, argv, nn, MCP_FROM_SERVER); rel_age = 0; } else { rel_age = -1; @@ -381,7 +603,7 @@ AddChannel(const char *name, time_t time_, const char *modes, char *banlist) /* if it's a new or updated channel, make callbacks */ if (rel_age > 0) for (nn=0; nn= 0)) { @@ -400,25 +622,46 @@ AddChannel(const char *name, time_t time_, const char *modes, char *banlist) } } + /* go through list of exempts and add each one */ + if (exemptlist && (rel_age >= 0)) { + for (nn=0; exemptlist[nn];) { + char *exempt = exemptlist + nn; + struct exemptNode *en; + while (exemptlist[nn] != ' ' && exemptlist[nn]) + nn++; + while (exemptlist[nn] == ' ') + exemptlist[nn++] = 0; + en = calloc(1, sizeof(*en)); + safestrncpy(en->exempt, exempt, sizeof(en->exempt)); + safestrncpy(en->who, "", sizeof(en->who)); + en->set = now; + exemptList_append(&cNode->exemptlist, en); + } + } + return cNode; } static del_channel_func_t *dcf_list; +static void **dcf_list_extra; static unsigned int dcf_size = 0, dcf_used = 0; void -reg_del_channel_func(del_channel_func_t handler) +reg_del_channel_func(del_channel_func_t handler, void *extra) { if (dcf_used == dcf_size) { if (dcf_size) { dcf_size <<= 1; dcf_list = realloc(dcf_list, dcf_size*sizeof(dcf_list[0])); + dcf_list_extra = realloc(dcf_list_extra, dcf_size*sizeof(void*)); } else { dcf_size = 8; dcf_list = malloc(dcf_size*sizeof(dcf_list[0])); + dcf_list_extra = malloc(dcf_size*sizeof(dcf_list_extra[0])); } } - dcf_list[dcf_used++] = handler; + dcf_list[dcf_used] = handler; + dcf_list_extra[dcf_used++] = extra; } static void @@ -426,6 +669,7 @@ DelChannel(struct chanNode *channel) { unsigned int n; + verify(channel); dict_remove(channels, channel->name); if (channel->members.used || channel->locks) { @@ -434,18 +678,24 @@ DelChannel(struct chanNode *channel) /* go through all channel members and delete them from the channel */ for (n=channel->members.used; n>0; ) - DelChannelUser(channel->members.list[--n]->user, channel, false, 1); + DelChannelUser(channel->members.list[--n]->user, channel, NULL, 1); /* delete all channel bans */ for (n=channel->banlist.used; n>0; ) free(channel->banlist.list[--n]); channel->banlist.used = 0; + /* delete all channel exempts */ + for (n=channel->exemptlist.used; n>0; ) + free(channel->exemptlist.list[--n]); + channel->exemptlist.used = 0; + for (n=0; nmembers); banList_clean(&channel->banlist); + exemptList_clean(&channel->exemptlist); free(channel); } @@ -465,6 +715,7 @@ AddChannelUser(struct userNode *user, struct chanNode* channel) mNode->channel = channel; mNode->user = user; mNode->modes = 0; + mNode->oplevel = -1; mNode->idle_since = now; /* Add modeNode to channel and to user. @@ -474,50 +725,60 @@ AddChannelUser(struct userNode *user, struct chanNode* channel) modeList_append(&channel->members, mNode); modeList_append(&user->channels, mNode); - if (channel->members.used == 1) + if (channel->members.used == 1 + && !(channel->modes & MODE_REGISTERED) + && !(channel->modes & MODE_APASS)) { mNode->modes |= MODE_CHANOP; + log_module(MAIN_LOG, LOG_DEBUG, "setting op"); + } - for (n=0; ndead; n++) { /* Callbacks return true if they kick or kill the user, * and we can continue without removing mNode. */ - if (jf_list[n](mNode)) + if (jf_list[n](mNode, jf_list_extra[n])) return NULL; } - if (IsLocal(user)) - irc_join(user, channel); - return mNode; } static part_func_t *pf_list; +static void **pf_list_extra; static unsigned int pf_size = 0, pf_used = 0; void -reg_part_func(part_func_t handler) +reg_part_func(part_func_t handler, void *extra) { if (pf_used == pf_size) { if (pf_size) { pf_size <<= 1; pf_list = realloc(pf_list, pf_size*sizeof(part_func_t)); + pf_list_extra = realloc(pf_list_extra, pf_size*sizeof(void*)); } else { pf_size = 8; pf_list = malloc(pf_size*sizeof(part_func_t)); + pf_list_extra = malloc(pf_size*sizeof(void*)); } } - pf_list[pf_used++] = handler; + pf_list[pf_used] = handler; + pf_list_extra[pf_used++] = extra; } void -unreg_part_func(part_func_t handler) +unreg_part_func(part_func_t handler, void *extra) { unsigned int i; for (i=0; imembers.used && !channel->locks && !(channel->modes & MODE_REGISTERED)) + /* A single check for APASS only should be enough here */ + if (!deleting && !channel->members.used && !channel->locks + && !(channel->modes & MODE_REGISTERED) && !(channel->modes & MODE_APASS)) DelChannel(channel); } +static kick_func_t *kf_list; +static void **kf_list_extra; +static unsigned int kf_size = 0, kf_used = 0; + void KickChannelUser(struct userNode* target, struct chanNode* channel, struct userNode *kicker, const char *why) { + unsigned int n; + if (!target || !channel || IsService(target) || !GetUserMode(channel, target)) return; + + /* This may break things, but lets see.. -Rubin */ + for (n=0; nidle_since = now; for (n=0; nexemptlist.used; n++) + if (match_ircglobs(channel->exemptlist.list[n]->exempt, exempt)) + return 1; + return 0; +} + static topic_func_t *tf_list; +static void **tf_list_extra; static unsigned int tf_size = 0, tf_used = 0; void -reg_topic_func(topic_func_t handler) +reg_topic_func(topic_func_t handler, void *extra) { if (tf_used == tf_size) { if (tf_size) { tf_size <<= 1; tf_list = realloc(tf_list, tf_size*sizeof(topic_func_t)); + tf_list_extra = realloc(tf_list_extra, tf_size*sizeof(void*)); } else { tf_size = 8; tf_list = malloc(tf_size*sizeof(topic_func_t)); + tf_list_extra = malloc(tf_size*sizeof(void*)); } } - tf_list[tf_used++] = handler; + tf_list[tf_used] = handler; + tf_list_extra[tf_used++] = extra; } void -SetChannelTopic(struct chanNode *channel, struct userNode *user, const char *topic, int announce) +SetChannelTopic(struct chanNode *channel, struct userNode *service, struct userNode *user, const char *topic, int announce) { unsigned int n; struct modeNode *mn; @@ -673,10 +961,14 @@ SetChannelTopic(struct chanNode *channel, struct userNode *user, const char *top if (announce) { /* We don't really care if a local user messes with the topic, * so don't call the tf_list functions. */ - irc_topic(user, channel, topic); + irc_topic(service, user, channel, topic); } else { for (n=0; nmembers.list); + verify(user); + verify(user->channels.list); if (channel->members.used < user->channels.used) { for (n=0; nmembers.used; n++) { + verify(channel->members.list[n]); if (user == channel->members.list[n]->user) { mn = channel->members.list[n]; break; @@ -701,6 +999,7 @@ GetUserMode(struct chanNode *channel, struct userNode *user) } } else { for (n=0; nchannels.used; n++) { + verify(user->channels.list[n]); if (channel == user->channels.list[n]->channel) { mn = user->channels.list[n]; break; @@ -710,14 +1009,41 @@ GetUserMode(struct chanNode *channel, struct userNode *user) return mn; } +struct userNode *IsInChannel(struct chanNode *channel, struct userNode *user) +{ + unsigned int n; + + verify(channel); + verify(channel->members.list); + verify(user); + verify(user->channels.list); + if (channel->members.used < user->channels.used) { + for (n=0; nmembers.used; n++) { + verify(channel->members.list[n]); + if (user == channel->members.list[n]->user) { + return(user); + } + } + } else { + for (n=0; nchannels.used; n++) { + verify(user->channels.list[n]); + if (channel == user->channels.list[n]->channel) { + return(user); + } + } + } + return NULL; +} + DEFINE_LIST(userList, struct userNode*) DEFINE_LIST(modeList, struct modeNode*) DEFINE_LIST(banList, struct banNode*) +DEFINE_LIST(exemptList, struct exemptNode*) DEFINE_LIST(channelList, struct chanNode*) DEFINE_LIST(serverList, struct server*) static void -hash_cleanup(void) +hash_cleanup(UNUSED_ARG(void *extra)) { dict_iterator_t it, next; @@ -732,13 +1058,23 @@ hash_cleanup(void) userList_clean(&curr_opers); free(slf_list); + free(slf_list_extra); free(nuf_list); + free(nuf_list_extra); free(ncf2_list); + free(ncf2_list_extra); free(duf_list); + free(duf_list_extra); free(ncf_list); + free(ncf_list_extra); free(jf_list); + free(jf_list_extra); free(dcf_list); + free(dcf_list_extra); free(pf_list); + free(pf_list_extra); free(kf_list); + free(kf_list_extra); free(tf_list); + free(tf_list_extra); }