1 /* hash.c - IRC network state database
2 * Copyright 2000-2004 srvx Development Team
4 * This file is part of x3.
6 * srvx 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 2 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.
30 unsigned int max_clients
, invis_clients
;
31 time_t max_clients_time
;
32 struct userList curr_opers
;
34 static void hash_cleanup(void);
36 void init_structs(void)
38 channels
= dict_new();
41 userList_init(&curr_opers
);
42 reg_exit_func(hash_cleanup
);
45 server_link_func_t
*slf_list
;
46 unsigned int slf_size
= 0, slf_used
= 0;
49 reg_server_link_func(server_link_func_t handler
)
51 if (slf_used
== slf_size
) {
54 slf_list
= realloc(slf_list
, slf_size
*sizeof(server_link_func_t
));
57 slf_list
= malloc(slf_size
*sizeof(server_link_func_t
));
60 slf_list
[slf_used
++] = handler
;
64 GetServerH(const char *name
)
66 return dict_find(servers
, name
, NULL
);
69 new_user_func_t
*nuf_list
;
70 unsigned int nuf_size
= 0, nuf_used
= 0;
73 reg_new_user_func(new_user_func_t handler
)
75 if (nuf_used
== nuf_size
) {
78 nuf_list
= realloc(nuf_list
, nuf_size
*sizeof(new_user_func_t
));
81 nuf_list
= malloc(nuf_size
*sizeof(new_user_func_t
));
84 nuf_list
[nuf_used
++] = handler
;
87 static nick_change_func_t
*ncf2_list
;
88 static unsigned int ncf2_size
= 0, ncf2_used
= 0;
91 reg_nick_change_func(nick_change_func_t handler
)
93 if (ncf2_used
== ncf2_size
) {
96 ncf2_list
= realloc(ncf2_list
, ncf2_size
*sizeof(nick_change_func_t
));
99 ncf2_list
= malloc(ncf2_size
*sizeof(nick_change_func_t
));
102 ncf2_list
[ncf2_used
++] = handler
;
106 del_user_func_t
*duf_list
;
107 unsigned int duf_size
= 0, duf_used
= 0;
110 reg_del_user_func(del_user_func_t handler
)
112 if (duf_used
== duf_size
) {
115 duf_list
= realloc(duf_list
, duf_size
*sizeof(del_user_func_t
));
118 duf_list
= malloc(duf_size
*sizeof(del_user_func_t
));
121 duf_list
[duf_used
++] = handler
;
125 unreg_del_user_func(del_user_func_t handler
)
128 for (i
=0; i
<duf_used
; i
++) {
129 if (duf_list
[i
] == handler
) break;
131 if (i
== duf_used
) return;
132 memmove(duf_list
+i
, duf_list
+i
+1, (duf_used
-i
-1)*sizeof(duf_list
[0]));
136 /* reintroduces a user after it has been killed. */
138 ReintroduceUser(struct userNode
*user
)
140 struct mod_chanmode change
;
144 mod_chanmode_init(&change
);
146 for (n
= 0; n
< user
->channels
.used
; n
++) {
147 struct modeNode
*mn
= user
->channels
.list
[n
];
148 irc_join(user
, mn
->channel
);
150 change
.args
[0].mode
= mn
->modes
;
151 change
.args
[0].u
.member
= mn
;
152 mod_chanmode_announce(user
, mn
->channel
, &change
);
158 NickChange(struct userNode
* user
, const char *new_nick
, int no_announce
)
163 /* don't do anything if there's no change */
164 old_nick
= user
->nick
;
165 if (!strncmp(new_nick
, old_nick
, NICKLEN
))
168 /* remove old entry from clients dictionary */
169 dict_remove(clients
, old_nick
);
170 #if !defined(WITH_PROTOCOL_P10)
171 /* Remove from uplink's clients dict */
172 dict_remove(user
->uplink
->users
, old_nick
);
175 user
->nick
= strdup(new_nick
);
176 dict_insert(clients
, user
->nick
, user
);
177 #if !defined(WITH_PROTOCOL_P10)
178 dict_insert(user
->uplink
->users
, user
->nick
, user
);
181 /* Make callbacks for nick changes. Do this with new nick in
182 * place because that is slightly more useful.
184 for (nn
=0; nn
<ncf2_used
; nn
++)
185 ncf2_list
[nn
](user
, old_nick
);
186 user
->timestamp
= now
;
187 if (IsLocal(user
) && !no_announce
)
188 irc_nick(user
, old_nick
);
193 GetUserH(const char *nick
)
195 return dict_find(clients
, nick
, NULL
);
198 static account_func_t account_func
;
201 reg_account_func(account_func_t handler
)
204 log_module(MAIN_LOG
, LOG_WARNING
, "Reregistering ACCOUNT handler.");
206 account_func
= handler
;
210 call_account_func(struct userNode
*user
, const char *stamp
)
212 /* We've received an account stamp for a user; notify
213 NickServ, which registers the sole account_func
216 P10 Protocol violation if (user->modes & FLAGS_STAMPED) here.
219 account_func(user
, stamp
);
221 #ifdef WITH_PROTOCOL_P10
222 /* Mark the user so we don't stamp it again. */
223 user
->modes
|= FLAGS_STAMPED
;
228 StampUser(struct userNode
*user
, const char *stamp
, time_t timestamp
)
230 #ifdef WITH_PROTOCOL_P10
231 /* The P10 protocol says we can't stamp users who already
237 irc_account(user
, stamp
, timestamp
);
238 user
->modes
|= FLAGS_STAMPED
;
242 assign_fakehost(struct userNode
*user
, const char *host
, int announce
)
244 safestrncpy(user
->fakehost
, host
, sizeof(user
->fakehost
));
246 irc_fakehost(user
, host
);
249 static new_channel_func_t
*ncf_list
;
250 static unsigned int ncf_size
= 0, ncf_used
= 0;
253 reg_new_channel_func(new_channel_func_t handler
)
255 if (ncf_used
== ncf_size
) {
258 ncf_list
= realloc(ncf_list
, ncf_size
*sizeof(ncf_list
[0]));
261 ncf_list
= malloc(ncf_size
*sizeof(ncf_list
[0]));
264 ncf_list
[ncf_used
++] = handler
;
267 static join_func_t
*jf_list
;
268 static unsigned int jf_size
= 0, jf_used
= 0;
271 reg_join_func(join_func_t handler
)
273 if (jf_used
== jf_size
) {
276 jf_list
= realloc(jf_list
, jf_size
*sizeof(join_func_t
));
279 jf_list
= malloc(jf_size
*sizeof(join_func_t
));
282 jf_list
[jf_used
++] = handler
;
288 wipeout_channel(struct chanNode
*cNode
, time_t new_time
, char **modes
, unsigned int modec
) {
289 unsigned int orig_limit
;
290 chan_mode_t orig_modes
;
291 char orig_key
[KEYLEN
+1];
292 unsigned int nn
, argc
;
295 cNode
->topic
[0] = '\0';
296 cNode
->topic_nick
[0] = '\0';
297 cNode
->topic_time
= 0;
299 /* remember the old modes, and update them with the new */
300 orig_modes
= cNode
->modes
;
301 orig_limit
= cNode
->limit
;
302 strcpy(orig_key
, cNode
->key
);
304 mod_chanmode(NULL
, cNode
, modes
, modec
, 0);
305 cNode
->timestamp
= new_time
;
307 /* remove our old ban list, replace it with the new one */
308 for (nn
=0; nn
<cNode
->banlist
.used
; nn
++)
309 free(cNode
->banlist
.list
[nn
]);
310 cNode
->banlist
.used
= 0;
312 /* remove our old exe,[t list, replace it with the new one */
313 for (nn
=0; nn
<cNode
->exemptlist
.used
; nn
++)
314 free(cNode
->exemptlist
.list
[nn
]);
315 cNode
->exemptlist
.used
= 0;
317 /* deop anybody in the channel now, but count services to reop */
318 for (nn
=argc
=0; nn
<cNode
->members
.used
; nn
++) {
319 struct modeNode
*mn
= cNode
->members
.list
[nn
];
320 if ((mn
->modes
& MODE_CHANOP
) && IsService(mn
->user
) && IsLocal(mn
->user
))
325 struct mod_chanmode
*change
;
327 change
= mod_chanmode_alloc(argc
);
328 change
->modes_clear
= 0;
329 change
->modes_set
= orig_modes
;
330 change
->new_limit
= orig_limit
;
331 strcpy(change
->new_key
, orig_key
);
332 for (nn
= argc
= 0; nn
< cNode
->members
.used
; ++nn
) {
333 struct modeNode
*mn
= cNode
->members
.list
[nn
];
334 if ((mn
->modes
& MODE_CHANOP
) && IsService(mn
->user
) && IsLocal(mn
->user
)) {
335 change
->args
[argc
].mode
= MODE_CHANOP
;
336 change
->args
[argc
].u
.member
= mn
;
340 assert(argc
== change
->argc
);
341 change
->args
[0].u
.member
->modes
&= ~MODE_CHANOP
;
342 mod_chanmode_announce(change
->args
[0].u
.member
->user
, cNode
, change
);
343 mod_chanmode_free(change
);
348 AddChannel(const char *name
, time_t time_
, const char *modes
, char *banlist
, char *exemptlist
)
350 struct chanNode
*cNode
;
351 char new_modes
[MAXLEN
], *argv
[MAXNUMPARAMS
];
354 if (!IsChannelName(name
)) {
355 log_module(MAIN_LOG
, LOG_ERROR
, "Somebody asked to add channel '%s', which isn't a channel name!", name
);
361 safestrncpy(new_modes
, modes
, sizeof(new_modes
));
362 nn
= split_line(new_modes
, 0, ArrayLength(argv
), argv
);
363 if (!(cNode
= GetChannel(name
))) {
364 cNode
= calloc(1, sizeof(*cNode
) + strlen(name
));
365 strcpy(cNode
->name
, name
);
366 banList_init(&cNode
->banlist
);
367 exemptList_init(&cNode
->exemptlist
);
368 modeList_init(&cNode
->members
);
369 mod_chanmode(NULL
, cNode
, argv
, nn
, 0);
370 dict_insert(channels
, cNode
->name
, cNode
);
371 cNode
->timestamp
= time_
;
373 } else if (cNode
->timestamp
> time_
) {
374 wipeout_channel(cNode
, time_
, argv
, nn
);
376 } else if (cNode
->timestamp
== time_
) {
377 mod_chanmode(NULL
, cNode
, argv
, nn
, 0);
383 /* rel_age is the relative ages of our channel data versus what is
384 * in a BURST command. 1 means ours is younger, 0 means both are
385 * the same age, -1 means ours is older. */
387 /* if it's a new or updated channel, make callbacks */
389 for (nn
=0; nn
<ncf_used
; nn
++)
392 /* go through list of bans and add each one */
393 if (banlist
&& (rel_age
>= 0)) {
394 for (nn
=0; banlist
[nn
];) {
395 char *ban
= banlist
+ nn
;
397 while (banlist
[nn
] != ' ' && banlist
[nn
])
399 while (banlist
[nn
] == ' ')
401 bn
= calloc(1, sizeof(*bn
));
402 safestrncpy(bn
->ban
, ban
, sizeof(bn
->ban
));
403 safestrncpy(bn
->who
, "<unknown>", sizeof(bn
->who
));
405 banList_append(&cNode
->banlist
, bn
);
409 /* go through list of exempts and add each one */
410 if (exemptlist
&& (rel_age
>= 0)) {
411 for (nn
=0; exemptlist
[nn
];) {
412 char *exempt
= exemptlist
+ nn
;
413 struct exemptNode
*en
;
414 while (exemptlist
[nn
] != ' ' && exemptlist
[nn
])
416 while (exemptlist
[nn
] == ' ')
417 exemptlist
[nn
++] = 0;
418 en
= calloc(1, sizeof(*en
));
419 safestrncpy(en
->exempt
, exempt
, sizeof(en
->exempt
));
420 safestrncpy(en
->who
, "<unknown>", sizeof(en
->who
));
422 exemptList_append(&cNode
->exemptlist
, en
);
429 static del_channel_func_t
*dcf_list
;
430 static unsigned int dcf_size
= 0, dcf_used
= 0;
433 reg_del_channel_func(del_channel_func_t handler
)
435 if (dcf_used
== dcf_size
) {
438 dcf_list
= realloc(dcf_list
, dcf_size
*sizeof(dcf_list
[0]));
441 dcf_list
= malloc(dcf_size
*sizeof(dcf_list
[0]));
444 dcf_list
[dcf_used
++] = handler
;
448 DelChannel(struct chanNode
*channel
)
452 dict_remove(channels
, channel
->name
);
454 if (channel
->members
.used
|| channel
->locks
) {
455 log_module(MAIN_LOG
, LOG_ERROR
, "Warning: deleting channel %s with %d users and %d locks remaining.", channel
->name
, channel
->members
.used
, channel
->locks
);
458 /* go through all channel members and delete them from the channel */
459 for (n
=channel
->members
.used
; n
>0; )
460 DelChannelUser(channel
->members
.list
[--n
]->user
, channel
, false, 1);
462 /* delete all channel bans */
463 for (n
=channel
->banlist
.used
; n
>0; )
464 free(channel
->banlist
.list
[--n
]);
465 channel
->banlist
.used
= 0;
467 /* delete all channel exempts */
468 for (n
=channel
->exemptlist
.used
; n
>0; )
469 free(channel
->exemptlist
.list
[--n
]);
470 channel
->exemptlist
.used
= 0;
472 for (n
=0; n
<dcf_used
; n
++)
473 dcf_list
[n
](channel
);
475 modeList_clean(&channel
->members
);
476 banList_clean(&channel
->banlist
);
477 exemptList_clean(&channel
->exemptlist
);
482 AddChannelUser(struct userNode
*user
, struct chanNode
* channel
)
484 struct modeNode
*mNode
;
487 mNode
= GetUserMode(channel
, user
);
491 mNode
= malloc(sizeof(*mNode
));
493 /* set up modeNode */
494 mNode
->channel
= channel
;
497 mNode
->idle_since
= now
;
499 /* Add modeNode to channel and to user.
500 * We have to do this before calling join funcs in case the
501 * modeNode is manipulated (e.g. chanserv ops the user).
503 modeList_append(&channel
->members
, mNode
);
504 modeList_append(&user
->channels
, mNode
);
506 if (channel
->members
.used
== 1
507 && !(channel
->modes
& MODE_REGISTERED
))
508 mNode
->modes
|= MODE_CHANOP
;
510 for (n
=0; n
<jf_used
; n
++) {
511 /* Callbacks return true if they kick or kill the user,
512 * and we can continue without removing mNode. */
513 if (jf_list
[n
](mNode
))
518 irc_join(user
, channel
);
523 static part_func_t
*pf_list
;
524 static unsigned int pf_size
= 0, pf_used
= 0;
527 reg_part_func(part_func_t handler
)
529 if (pf_used
== pf_size
) {
532 pf_list
= realloc(pf_list
, pf_size
*sizeof(part_func_t
));
535 pf_list
= malloc(pf_size
*sizeof(part_func_t
));
538 pf_list
[pf_used
++] = handler
;
542 unreg_part_func(part_func_t handler
)
545 for (i
=0; i
<pf_used
; i
++)
546 if (pf_list
[i
] == handler
)
550 memmove(pf_list
+i
, pf_list
+i
+1, (pf_used
-i
-1)*sizeof(pf_list
[0]));
555 LockChannel(struct chanNode
* channel
)
561 UnlockChannel(struct chanNode
*channel
)
563 assert(channel
->locks
> 0);
564 if (!--channel
->locks
&& !channel
->members
.used
)
569 DelChannelUser(struct userNode
* user
, struct chanNode
* channel
, const char *reason
, int deleting
)
571 struct modeNode
* mNode
;
575 irc_part(user
, channel
, reason
);
577 mNode
= GetUserMode(channel
, user
);
579 /* Sometimes we get a PART when the user has been KICKed.
580 * In this case, we get no usermode, and should not try to free it.
585 /* remove modeNode from channel and user */
586 modeList_remove(&channel
->members
, mNode
);
587 modeList_remove(&user
->channels
, mNode
);
590 for (n
=0; n
<pf_used
; n
++)
591 pf_list
[n
](mNode
, reason
);
596 if (!deleting
&& !channel
->members
.used
&& !channel
->locks
&& !(channel
->modes
& MODE_REGISTERED
))
601 KickChannelUser(struct userNode
* target
, struct chanNode
* channel
, struct userNode
*kicker
, const char *why
)
603 if (!target
|| !channel
|| IsService(target
) || !GetUserMode(channel
, target
))
605 /* don't remove them from the channel, since the server will send a PART */
606 irc_kick(kicker
, target
, channel
, why
);
610 /* NULL reason because we don't want a PART message to be
611 sent by DelChannelUser. */
612 DelChannelUser(target
, channel
, NULL
, 0);
616 static kick_func_t
*kf_list
;
617 static unsigned int kf_size
= 0, kf_used
= 0;
620 reg_kick_func(kick_func_t handler
)
622 if (kf_used
== kf_size
) {
625 kf_list
= realloc(kf_list
, kf_size
*sizeof(kick_func_t
));
628 kf_list
= malloc(kf_size
*sizeof(kick_func_t
));
631 kf_list
[kf_used
++] = handler
;
635 ChannelUserKicked(struct userNode
* kicker
, struct userNode
* victim
, struct chanNode
* channel
)
640 if (!victim
|| !channel
|| IsService(victim
) || !GetUserMode(channel
, victim
))
643 /* Update the kicker's idle time (kicker may be null if it was a server) */
644 if (kicker
&& (mn
= GetUserMode(channel
, kicker
)))
645 mn
->idle_since
= now
;
647 for (n
=0; n
<kf_used
; n
++)
648 kf_list
[n
](kicker
, victim
, channel
);
650 DelChannelUser(victim
, channel
, 0, 0);
653 irc_part(victim
, channel
, NULL
);
656 int ChannelBanExists(struct chanNode
*channel
, const char *ban
)
660 for (n
= 0; n
< channel
->banlist
.used
; n
++)
661 if (match_ircglobs(channel
->banlist
.list
[n
]->ban
, ban
))
666 int ChannelExemptExists(struct chanNode
*channel
, const char *exempt
)
670 for (n
= 0; n
< channel
->exemptlist
.used
; n
++)
671 if (match_ircglobs(channel
->exemptlist
.list
[n
]->exempt
, exempt
))
676 static topic_func_t
*tf_list
;
677 static unsigned int tf_size
= 0, tf_used
= 0;
680 reg_topic_func(topic_func_t handler
)
682 if (tf_used
== tf_size
) {
685 tf_list
= realloc(tf_list
, tf_size
*sizeof(topic_func_t
));
688 tf_list
= malloc(tf_size
*sizeof(topic_func_t
));
691 tf_list
[tf_used
++] = handler
;
695 SetChannelTopic(struct chanNode
*channel
, struct userNode
*service
, struct userNode
*user
, const char *topic
, int announce
)
699 char old_topic
[TOPICLEN
+1];
701 safestrncpy(old_topic
, channel
->topic
, sizeof(old_topic
));
702 safestrncpy(channel
->topic
, topic
, sizeof(channel
->topic
));
703 channel
->topic_time
= now
;
706 safestrncpy(channel
->topic_nick
, user
->nick
, sizeof(channel
->topic_nick
));
708 /* Update the setter's idle time */
709 if ((mn
= GetUserMode(channel
, user
)))
710 mn
->idle_since
= now
;
714 /* We don't really care if a local user messes with the topic,
715 * so don't call the tf_list functions. */
716 irc_topic(service
, user
, channel
, topic
);
718 for (n
=0; n
<tf_used
; n
++)
719 if (tf_list
[n
](user
, channel
, old_topic
))
725 GetChannel(const char *name
)
727 return dict_find(channels
, name
, NULL
);
731 GetUserMode(struct chanNode
*channel
, struct userNode
*user
)
734 struct modeNode
*mn
= NULL
;
737 verify(channel
->members
.list
);
739 verify(user
->channels
.list
);
740 if (channel
->members
.used
< user
->channels
.used
) {
741 for (n
=0; n
<channel
->members
.used
; n
++) {
742 verify(channel
->members
.list
[n
]);
743 if (user
== channel
->members
.list
[n
]->user
) {
744 mn
= channel
->members
.list
[n
];
749 for (n
=0; n
<user
->channels
.used
; n
++) {
750 verify(user
->channels
.list
[n
]);
751 if (channel
== user
->channels
.list
[n
]->channel
) {
752 mn
= user
->channels
.list
[n
];
760 struct userNode
*IsInChannel(struct chanNode
*channel
, struct userNode
*user
)
765 verify(channel
->members
.list
);
767 verify(user
->channels
.list
);
768 if (channel
->members
.used
< user
->channels
.used
) {
769 for (n
=0; n
<channel
->members
.used
; n
++) {
770 verify(channel
->members
.list
[n
]);
771 if (user
== channel
->members
.list
[n
]->user
) {
776 for (n
=0; n
<user
->channels
.used
; n
++) {
777 verify(user
->channels
.list
[n
]);
778 if (channel
== user
->channels
.list
[n
]->channel
) {
786 DEFINE_LIST(userList
, struct userNode
*)
787 DEFINE_LIST(modeList
, struct modeNode
*)
788 DEFINE_LIST(banList
, struct banNode
*)
789 DEFINE_LIST(exemptList
, struct exemptNode
*)
790 DEFINE_LIST(channelList
, struct chanNode
*)
791 DEFINE_LIST(serverList
, struct server
*)
796 dict_iterator_t it
, next
;
798 DelServer(self
, 0, NULL
);
799 for (it
= dict_first(channels
); it
; it
= next
) {
800 next
= iter_next(it
);
801 DelChannel(iter_data(it
));
803 dict_delete(channels
);
804 dict_delete(clients
);
805 dict_delete(servers
);
806 userList_clean(&curr_opers
);