1 /************
2 * hash.c *
3 ************
4 *
5 * My hash routines for hashing NickLists, and eventually ChannelList's
6 * and WhowasList's
7 *
8 * These are not very robust, as the add/remove functions will have
9 * to be written differently for each type of struct
10 * (To DO: use C++, and create a hash "class" so I don't need to
11 * have the functions different.)
12 *
13 *
14 * Written by Scott H Kilau
15 *
16 * Copyright(c) 1997
17 *
18 * Modified by Colten Edwards for use in BitchX.
19 * Added Whowas buffer hashing.
20 *
21 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
22 */
23
24 #include "irc.h"
25 static char cvsrevision[] = "$Id: hash.c 52 2008-06-14 06:45:05Z keaston $";
CVS_REVISION(hash_c)26 CVS_REVISION(hash_c)
27 #include "struct.h"
28 #include "ircaux.h"
29 #include "hook.h"
30 #include "vars.h"
31 #include "output.h"
32 #include "misc.h"
33 #include "server.h"
34 #include "list.h"
35 #include "window.h"
36
37 #include "hash.h"
38 #include "hash2.h"
39 #define MAIN_SOURCE
40 #include "modval.h"
41
42 /*
43 * hash_nickname: for now, does a simple hash of the
44 * nick by counting up the ascii values of the lower case, and
45 * then %'ing it by NICKLIST_HASHSIZE (always a prime!)
46 */
47 unsigned long hash_nickname(char *nick, unsigned int size)
48 {
49 register u_char *p = (u_char *) nick;
50 unsigned long hash = 0, g;
51 if (!nick) return -1;
52 while (*p)
53 {
54 hash = (hash << 4) + ((*p >= 'A' && *p <= 'Z') ? (*p+32) : *p);
55 if ((g = hash & 0xF0000000))
56 hash ^= g >> 24;
57 hash &= ~g;
58 p++;
59 }
60 return (hash %= size);
61 }
62
63 /*
64 * move_link_to_top: used by find routine, brings link
65 * to the top of the list in the specific array location
66 */
move_link_to_top(NickList * tmp,NickList * prev,HashEntry * location)67 static inline void move_link_to_top(NickList *tmp, NickList *prev, HashEntry *location)
68 {
69 if (prev)
70 {
71 NickList *old_list;
72 old_list = (NickList *) location->list;
73 location->list = (void *) tmp;
74 prev->next = tmp->next;
75 tmp->next = old_list;
76 }
77 }
78
79 /*
80 * remove_link_from_list: used by find routine, removes link
81 * from our chain of hashed entries.
82 */
remove_link_from_list(NickList * tmp,NickList * prev,HashEntry * location)83 static inline void remove_link_from_list(NickList *tmp, NickList *prev, HashEntry *location)
84 {
85 if (prev)
86 {
87 /* remove the link from the middle of the list */
88 prev->next = tmp->next;
89 }
90 else {
91 /* unlink the first link, and connect next one up */
92 location->list = (void *) tmp->next;
93 }
94 /* set tmp's next to NULL, as its unlinked now */
95 tmp->next = NULL;
96 }
97
BX_add_name_to_genericlist(char * name,HashEntry * list,unsigned int size)98 void BX_add_name_to_genericlist(char *name, HashEntry *list, unsigned int size)
99 {
100 List *nptr;
101 unsigned long hvalue = hash_nickname(name, size);
102
103 nptr = (List *) new_malloc(sizeof(List));
104 nptr->next = (List *) list[hvalue].list;
105 nptr->name = m_strdup(name);
106
107 /* assign our new linked list into array spot */
108 list[hvalue].list = (void *) nptr;
109 /* quick tally of nicks in chain in this array spot */
110 list[hvalue].links++;
111 /* keep stats on hits to this array spot */
112 list[hvalue].hits++;
113 }
114
115 /*
116 * move_link_to_top: used by find routine, brings link
117 * to the top of the list in the specific array location
118 */
move_gen_link_to_top(List * tmp,List * prev,HashEntry * location)119 static inline void move_gen_link_to_top(List *tmp, List *prev, HashEntry *location)
120 {
121 if (prev)
122 {
123 List *old_list;
124 old_list = (List *) location->list;
125 location->list = (void *) tmp;
126 prev->next = tmp->next;
127 tmp->next = old_list;
128 }
129 }
130
131 /*
132 * remove_link_from_list: used by find routine, removes link
133 * from our chain of hashed entries.
134 */
remove_gen_link_from_list(List * tmp,List * prev,HashEntry * location)135 static inline void remove_gen_link_from_list(List *tmp, List *prev, HashEntry *location)
136 {
137 if (prev)
138 {
139 /* remove the link from the middle of the list */
140 prev->next = tmp->next;
141 }
142 else {
143 /* unlink the first link, and connect next one up */
144 location->list = (void *) tmp->next;
145 }
146 /* set tmp's next to NULL, as its unlinked now */
147 tmp->next = NULL;
148 }
149
BX_find_name_in_genericlist(char * name,HashEntry * list,unsigned int size,int remove)150 List *BX_find_name_in_genericlist(char *name, HashEntry *list, unsigned int size, int remove)
151 {
152 HashEntry *location;
153 register List *tmp, *prev = NULL;
154 unsigned long hvalue = hash_nickname(name, size);
155
156 location = &(list[hvalue]);
157
158 /* at this point, we found the array spot, now search
159 * as regular linked list, or as ircd likes to say...
160 * "We found the bucket, now search the chain"
161 */
162 for (tmp = (List *) location->list; tmp; prev = tmp, tmp = tmp->next)
163 {
164 if (!my_stricmp(name, tmp->name))
165 {
166 if (remove != REMOVE_FROM_LIST)
167 move_gen_link_to_top(tmp, prev, location);
168 else
169 {
170 location->links--;
171 remove_gen_link_from_list(tmp, prev, location);
172 }
173 return tmp;
174 }
175 }
176 return NULL;
177 }
178
179 /*
180 * add_nicklist_to_channellist: This function will add the nicklist
181 * into the channellist, ensuring that we hash the nicklist, and
182 * insert the struct correctly into the channelist's Nicklist hash
183 * array
184 */
BX_add_nicklist_to_channellist(NickList * nptr,ChannelList * cptr)185 void BX_add_nicklist_to_channellist(NickList *nptr, ChannelList *cptr)
186 {
187 unsigned long hvalue = hash_nickname(nptr->nick, NICKLIST_HASHSIZE);
188
189 /* take this nicklist, and attach it as the HEAD pointer
190 * in our chain at the hashed location in our array...
191 * Note, by doing this, this ensures that the "most active"
192 * users always remain at the top of the chain... ie, faster
193 * lookups for active users, (and as a side note, makes
194 * doing the add quite simple!)
195 */
196 nptr->next = (NickList *) cptr->NickListTable[hvalue].list;
197
198 /* assign our new linked list into array spot */
199 cptr->NickListTable[hvalue].list = (void *) nptr;
200 /* quick tally of nicks in chain in this array spot */
201 cptr->NickListTable[hvalue].links++;
202 /* keep stats on hits to this array spot */
203 cptr->NickListTable[hvalue].hits++;
204 }
205
BX_find_nicklist_in_channellist(char * nick,ChannelList * cptr,int remove)206 NickList *BX_find_nicklist_in_channellist(char *nick, ChannelList *cptr, int remove)
207 {
208 HashEntry *location;
209 register NickList *tmp, *prev = NULL;
210 unsigned long hvalue = hash_nickname(nick, NICKLIST_HASHSIZE);
211
212 if (!cptr)
213 return NULL;
214 location = &(cptr->NickListTable[hvalue]);
215
216 /* at this point, we found the array spot, now search
217 * as regular linked list, or as ircd likes to say...
218 * "We found the bucket, now search the chain"
219 */
220 for (tmp = (NickList *) location->list; tmp; prev = tmp, tmp = tmp->next)
221 {
222 if (!my_stricmp(nick, tmp->nick))
223 {
224 if (remove != REMOVE_FROM_LIST)
225 move_link_to_top(tmp, prev, location);
226 else
227 {
228 location->links--;
229 remove_link_from_list(tmp, prev, location);
230 }
231 return tmp;
232 }
233 }
234 return NULL;
235 }
236
237 /*
238 * Basically this makes the hash table "look" like a straight linked list
239 * This should be used for things that require you to cycle through the
240 * full list, ex. for finding ALL matching stuff.
241 * : usage should be like :
242 *
243 * for (nptr = next_nicklist(cptr, NULL); nptr; nptr =
244 * next_nicklist(cptr, nptr))
245 * YourCodeOnTheNickListStruct
246 */
BX_next_nicklist(ChannelList * cptr,NickList * nptr)247 NickList *BX_next_nicklist(ChannelList *cptr, NickList *nptr)
248 {
249 unsigned long hvalue = 0;
250 if (!cptr)
251 /* No channel! */
252 return NULL;
253 else if (!nptr)
254 {
255 /* wants to start the walk! */
256 while ((NickList *) cptr->NickListTable[hvalue].list == NULL)
257 {
258 hvalue++;
259 if (hvalue >= NICKLIST_HASHSIZE)
260 return NULL;
261 }
262 return (NickList *) cptr->NickListTable[hvalue].list;
263 }
264 else if (nptr->next)
265 {
266 /* still returning a chain! */
267 return nptr->next;
268 }
269 else if (!nptr->next)
270 {
271 int hvalue;
272 /* hit end of chain, go to next bucket */
273 hvalue = hash_nickname(nptr->nick, NICKLIST_HASHSIZE) + 1;
274 if (hvalue >= NICKLIST_HASHSIZE)
275 {
276 /* end of list */
277 return NULL;
278 }
279 else
280 {
281 while ((NickList *) cptr->NickListTable[hvalue].list == NULL)
282 {
283 hvalue++;
284 if (hvalue >= NICKLIST_HASHSIZE)
285 return NULL;
286 }
287 /* return head of next filled bucket */
288 return (NickList *) cptr->NickListTable[hvalue].list;
289 }
290 }
291 else
292 /* shouldn't ever be here */
293 say ("HASH_ERROR: next_nicklist");
294 return NULL;
295 }
296
BX_next_namelist(HashEntry * cptr,List * nptr,unsigned int size)297 List *BX_next_namelist(HashEntry *cptr, List *nptr, unsigned int size)
298 {
299 unsigned long hvalue = 0;
300 if (!cptr)
301 /* No channel! */
302 return NULL;
303 else if (!nptr)
304 {
305 /* wants to start the walk! */
306 while ((List *) cptr[hvalue].list == NULL)
307 {
308 hvalue++;
309 if (hvalue >= size)
310 return NULL;
311 }
312 return (List *) cptr[hvalue].list;
313 }
314 else if (nptr->next)
315 {
316 /* still returning a chain! */
317 return nptr->next;
318 }
319 else if (!nptr->next)
320 {
321 int hvalue;
322 /* hit end of chain, go to next bucket */
323 hvalue = hash_nickname(nptr->name, size) + 1;
324 if (hvalue >= size)
325 {
326 /* end of list */
327 return NULL;
328 }
329 else
330 {
331 while ((List *) cptr[hvalue].list == NULL)
332 {
333 hvalue++;
334 if (hvalue >= size)
335 return NULL;
336 }
337 /* return head of next filled bucket */
338 return (List *) cptr[hvalue].list;
339 }
340 }
341 else
342 /* shouldn't ever be here */
343 say ("HASH_ERROR: next_namelist");
344 return NULL;
345 }
346
clear_nicklist_hashtable(ChannelList * cptr)347 void clear_nicklist_hashtable(ChannelList *cptr)
348 {
349 if (cptr)
350 {
351 memset((char *) cptr->NickListTable, 0,
352 sizeof(HashEntry) * NICKLIST_HASHSIZE);
353 }
354 }
355
356
show_nicklist_hashtable(ChannelList * cptr)357 void show_nicklist_hashtable(ChannelList *cptr)
358 {
359 int count, count2;
360 NickList *ptr;
361
362 for (count = 0; count < NICKLIST_HASHSIZE; count++)
363 {
364 if (cptr->NickListTable[count].links == 0)
365 continue;
366 say("HASH DEBUG: %d links %d hits %d",
367 count,
368 cptr->NickListTable[count].links,
369 cptr->NickListTable[count].hits);
370
371 for (ptr = (NickList *) cptr->NickListTable[count].list,
372 count2 = 0; ptr; count2++, ptr = ptr->next)
373 {
374 say("HASH_DEBUG: %d:%d %s!%s", count, count2,
375 ptr->nick, ptr->host);
376 }
377 }
378 }
379
show_whowas_debug_hashtable(WhowasWrapList * cptr)380 void show_whowas_debug_hashtable(WhowasWrapList *cptr)
381 {
382 int count, count2;
383 WhowasList *ptr;
384
385 for (count = 0; count < WHOWASLIST_HASHSIZE; count++)
386 {
387 if (cptr->NickListTable[count].links == 0)
388 continue;
389 say("HASH DEBUG: %d links %d hits %d",
390 count,
391 cptr->NickListTable[count].links,
392 cptr->NickListTable[count].hits);
393
394 for (ptr = (WhowasList *) cptr->NickListTable[count].list,
395 count2 = 0; ptr; count2++, ptr = ptr->next)
396 {
397 say("HASH_DEBUG: %d:%d %10s %s!%s", count, count2,
398 ptr->channel, ptr->nicklist->nick, ptr->nicklist->host);
399 }
400 }
401 }
402
BUILT_IN_COMMAND(show_hash)403 BUILT_IN_COMMAND(show_hash)
404 {
405 char *c;
406 ChannelList *chan = NULL, *chan2;
407 extern int from_server;
408 extern WhowasWrapList whowas_userlist_list;
409 extern WhowasWrapList whowas_reg_list;
410 extern WhowasWrapList whowas_splitin_list;
411 if (args && *args)
412 c = next_arg(args, &args);
413 else
414 c = get_current_channel_by_refnum(0);
415 if (c && from_server > -1)
416 {
417 chan2 = get_server_channels(from_server);
418 chan = (ChannelList *)find_in_list((List **)&chan2, c, 0);
419 }
420 if (chan)
421 show_nicklist_hashtable(chan);
422 show_whowas_debug_hashtable(&whowas_userlist_list);
423 show_whowas_debug_hashtable(&whowas_reg_list);
424 show_whowas_debug_hashtable(&whowas_splitin_list);
425 }
426
427 /*
428 * the following routines are written by Colten Edwards (panasync)
429 * to hash the whowas lists that the client keeps.
430 */
431
hash_userhost_channel(char * userhost,char * channel,unsigned int size)432 static unsigned long hash_userhost_channel(char *userhost, char *channel, unsigned int size)
433 {
434 register const unsigned char *p = (const unsigned char *)userhost;
435 unsigned long g, hash = 0;
436 if (!userhost) return -1;
437 while (*p)
438 {
439 hash = (hash << 4) + ((*p >= 'A' && *p <= 'Z') ? (*p+32) : *p);
440 if ((g = hash & 0xF0000000))
441 hash ^= g >> 24;
442 hash &= ~g;
443 p++;
444 }
445 p = (const unsigned char *)channel;
446 if (p)
447 {
448 while (*p)
449 {
450 if (*p == ',')
451 return -1;
452 hash = (hash << 4) + ((*p >= 'A' && *p <= 'Z') ? (*p+32) : *p);
453 if ((g = hash & 0xF0000000))
454 hash ^= g >> 24;
455 hash &= ~g;
456 p++;
457 }
458 }
459 return (hash % size);
460 }
461
462 /*
463 * move_link_to_top: used by find routine, brings link
464 * to the top of the list in the specific array location
465 */
move_link_to_top_whowas(WhowasList * tmp,WhowasList * prev,HashEntry * location)466 static inline void move_link_to_top_whowas(WhowasList *tmp, WhowasList *prev, HashEntry *location)
467 {
468 if (prev)
469 {
470 WhowasList *old_list;
471 old_list = (WhowasList *) location->list;
472 location->list = (void *) tmp;
473 prev->next = tmp->next;
474 tmp->next = old_list;
475 }
476 }
477
478 /*
479 * remove_link_from_list: used by find routine, removes link
480 * from our chain of hashed entries.
481 */
remove_link_from_whowaslist(WhowasList * tmp,WhowasList * prev,HashEntry * location)482 static inline void remove_link_from_whowaslist(WhowasList *tmp, WhowasList *prev, HashEntry *location)
483 {
484 if (prev)
485 {
486 /* remove the link from the middle of the list */
487 prev->next = tmp->next;
488 }
489 else {
490 /* unlink the first link, and connect next one up */
491 location->list = (void *) tmp->next;
492 }
493 /* set tmp's next to NULL, as its unlinked now */
494 tmp->next = NULL;
495 }
496
497 /*
498 * add_nicklist_to_channellist: This function will add the nicklist
499 * into the channellist, ensuring that we hash the nicklist, and
500 * insert the struct correctly into the channelist's Nicklist hash
501 * array
502 */
BX_add_whowas_userhost_channel(WhowasList * wptr,WhowasWrapList * list)503 void BX_add_whowas_userhost_channel(WhowasList *wptr, WhowasWrapList *list)
504 {
505 unsigned long hvalue = hash_userhost_channel(wptr->nicklist->host, wptr->channel, WHOWASLIST_HASHSIZE);
506
507 /* take this nicklist, and attach it as the HEAD pointer
508 * in our chain at the hashed location in our array...
509 * Note, by doing this, this ensures that the "most active"
510 * users always remain at the top of the chain... ie, faster
511 * lookups for active users, (and as a side note, makes
512 * doing the add quite simple!)
513 */
514 wptr->next = (WhowasList *) list->NickListTable[hvalue].list;
515
516 /* assign our new linked list into array spot */
517 list->NickListTable[hvalue].list = (void *) wptr;
518 /* quick tally of nicks in chain in this array spot */
519 list->NickListTable[hvalue].links++;
520 /* keep stats on hits to this array spot */
521 list->NickListTable[hvalue].hits++;
522 list->total_links++;
523 }
524
BX_find_userhost_channel(char * host,char * channel,int remove,WhowasWrapList * wptr)525 WhowasList *BX_find_userhost_channel(char *host, char *channel, int remove, WhowasWrapList *wptr)
526 {
527 HashEntry *location;
528 register WhowasList *tmp, *prev = NULL;
529 unsigned long hvalue;
530
531 hvalue = hash_userhost_channel(host, channel, WHOWASLIST_HASHSIZE);
532 location = &(wptr->NickListTable[hvalue]);
533
534 /* at this point, we found the array spot, now search
535 * as regular linked list, or as ircd likes to say...
536 * "We found the bucket, now search the chain"
537 */
538 for (tmp = (WhowasList *) (&(wptr->NickListTable[hvalue]))->list; tmp; prev = tmp, tmp = tmp->next)
539 {
540 if (!tmp->nicklist->host || !tmp->channel || !host || !channel)
541 continue;
542 if (!my_stricmp(host, tmp->nicklist->host) && !my_stricmp(channel, tmp->channel))
543 {
544 if (remove != REMOVE_FROM_LIST)
545 move_link_to_top_whowas(tmp, prev, location);
546 else
547 {
548 location->links--;
549 remove_link_from_whowaslist(tmp, prev, location);
550 wptr->total_unlinks++;
551 }
552 wptr->total_hits++;
553 return tmp;
554 }
555 }
556 return NULL;
557 }
558
559 /*
560 * Basically this makes the hash table "look" like a straight linked list
561 * This should be used for things that require you to cycle through the
562 * full list, ex. for finding ALL matching stuff.
563 * : usage should be like :
564 *
565 * for (nptr = next_userhost(cptr, NULL); nptr; nptr =
566 * next_userhost(cptr, nptr))
567 * YourCodeOnTheWhowasListStruct
568 */
BX_next_userhost(WhowasWrapList * cptr,WhowasList * nptr)569 WhowasList *BX_next_userhost(WhowasWrapList *cptr, WhowasList *nptr)
570 {
571 unsigned long hvalue = 0;
572 if (!cptr)
573 /* No channel! */
574 return NULL;
575 else if (!nptr)
576 {
577 /* wants to start the walk! */
578 while ((WhowasList *) cptr->NickListTable[hvalue].list == NULL)
579 {
580 hvalue++;
581 if (hvalue >= WHOWASLIST_HASHSIZE)
582 return NULL;
583 }
584 return (WhowasList *) cptr->NickListTable[hvalue].list;
585 }
586 else if (nptr->next)
587 {
588 /* still returning a chain! */
589 return nptr->next;
590 }
591 else if (!nptr->next)
592 {
593 int hvalue;
594 /* hit end of chain, go to next bucket */
595 hvalue = hash_userhost_channel(nptr->nicklist->host, nptr->channel, WHOWASLIST_HASHSIZE) + 1;
596 if (hvalue >= WHOWASLIST_HASHSIZE)
597 {
598 /* end of list */
599 return NULL;
600 }
601 else
602 {
603 while ((WhowasList *) cptr->NickListTable[hvalue].list == NULL)
604 {
605 hvalue++;
606 if (hvalue >= WHOWASLIST_HASHSIZE)
607 return NULL;
608 }
609 /* return head of next filled bucket */
610 return (WhowasList *) cptr->NickListTable[hvalue].list;
611 }
612 }
613 else
614 /* shouldn't ever be here */
615 say ("WHOWAS_HASH_ERROR: next_userhost");
616 return NULL;
617 }
618
show_whowas_hashtable(WhowasWrapList * cptr,char * list)619 void show_whowas_hashtable(WhowasWrapList *cptr, char *list)
620 {
621 int count, count2 = 1;
622 WhowasList *ptr;
623
624 say("WhoWas %s Cache Stats: %lu hits %lu links %lu unlinks", list, cptr->total_hits, cptr->total_links, cptr->total_unlinks);
625 for (count = 0; count < WHOWASLIST_HASHSIZE; count++)
626 {
627
628 if (cptr->NickListTable[count].links == 0)
629 continue;
630 for (ptr = (WhowasList *) cptr->NickListTable[count].list; ptr; count2++, ptr = ptr->next)
631 put_it("%s", convert_output_format("%K[%W$[3]0%K] %Y$[10]1 %W$2%G!%c$3", "%d %s %s %s", count2, ptr->channel, ptr->nicklist->nick, ptr->nicklist->host));
632 }
633 }
634
show_wholeft_hashtable(WhowasWrapList * cptr,time_t ltime,int * total,int * hook,char * list)635 int show_wholeft_hashtable(WhowasWrapList *cptr, time_t ltime, int *total, int *hook, char *list)
636 {
637 int count, count2;
638 WhowasList *ptr;
639
640 for (count = 0; count < WHOWASLIST_HASHSIZE; count++)
641 {
642
643 if (cptr->NickListTable[count].links == 0)
644 continue;
645 for (ptr = (WhowasList *) cptr->NickListTable[count].list, count2 = 1; ptr; count2++, ptr = ptr->next)
646 {
647 if (ptr->server1/* && ptr->server2*/)
648 {
649 if (!(*total)++ && (*hook = do_hook(WHOLEFT_HEADER_LIST, "%s %s %s %s %s %s", "Nick", "Host", "Channel", "Time", "Server", "Server")))
650 put_it("%s", convert_output_format(fget_string_var(FORMAT_WHOLEFT_HEADER_FSET), NULL));
651 if (do_hook(WHOLEFT_LIST, "%s %s %s %ld %s %s", ptr->nicklist->nick, ptr->nicklist->host, ptr->channel, ltime-ptr->time, ptr->server1?ptr->server1:"Unknown", ptr->server2?ptr->server2:"Unknown"))
652 put_it("%s", convert_output_format(fget_string_var(FORMAT_WHOLEFT_USER_FSET), "%s %s %s %l %s", ptr->nicklist->nick, ptr->nicklist->host, ptr->channel, (long)ltime-ptr->time, ptr->server1?ptr->server1:empty_string));
653 }
654 }
655 }
656 if (*total)
657 do_hook(WHOLEFT_FOOTER_LIST, "%s", "End of WhoLeft");
658 return *hook;
659 }
660
BX_remove_oldest_whowas_hashlist(WhowasWrapList * list,time_t timet,int count)661 int BX_remove_oldest_whowas_hashlist(WhowasWrapList *list, time_t timet, int count)
662 {
663 WhowasList *ptr;
664 int total = 0;
665 register unsigned long x;
666 if (!count)
667 {
668 for (x = 0; x < WHOWASLIST_HASHSIZE; x++)
669 {
670 ptr = (WhowasList *) (&(list->NickListTable[x]))->list;
671 if (!ptr || !ptr->nicklist)
672 continue;
673 while (ptr)
674 {
675 if ((ptr->time + timet) <= now)
676 {
677 if (!(ptr = find_userhost_channel(ptr->nicklist->host, ptr->channel, 1, list)))
678 break;
679 new_free(&(ptr->nicklist->ip));
680 new_free(&(ptr->nicklist->nick));
681 new_free(&(ptr->nicklist->host));
682 new_free(&(ptr->nicklist->server));
683 new_free((char **)&(ptr->nicklist));
684 new_free(&(ptr->channel));
685 new_free(&(ptr->server1));
686 new_free(&(ptr->server2));
687 new_free((char **)&ptr);
688 total++;
689 ptr = (WhowasList *) (&(list->NickListTable[x]))->list;
690 } else ptr = ptr->next;
691 }
692 }
693 }
694 else
695 {
696 while((ptr = next_userhost(list, NULL)) && count)
697 {
698 x = hash_userhost_channel(ptr->nicklist->host, ptr->channel, WHOWASLIST_HASHSIZE);
699 if (!(ptr = find_userhost_channel(ptr->nicklist->host, ptr->channel, 1, list)))
700 break;
701 if (ptr->nicklist)
702 {
703 new_free(&(ptr->nicklist->ip));
704 new_free(&(ptr->nicklist->nick));
705 new_free(&(ptr->nicklist->host));
706 new_free(&(ptr->nicklist->server));
707 new_free((char **)&(ptr->nicklist));
708 }
709 new_free(&(ptr->channel));
710 new_free(&(ptr->server1));
711 new_free(&(ptr->server2));
712 new_free((char **)&ptr);
713 total++; count--;
714 }
715 }
716 return total;
717 }
718
cmp_host(List * a,List * b)719 int cmp_host (List *a, List *b)
720 {
721 NickList *a1 = (NickList *)a, *b1 = (NickList *)b;
722 return strcmp(a1->host, b1->host);
723 }
724
cmp_time(List * a,List * b)725 int cmp_time (List *a, List *b)
726 {
727 NickList *a1 = (NickList *)a, *b1 = (NickList *)b;
728 if (a1->idle_time > b1->idle_time)
729 return -1;
730 if (a1->idle_time < b1->idle_time)
731 return 1;
732 return strcmp(a1->nick, b1->nick);
733 }
734
735
cmp_ip(List * a,List * b)736 int cmp_ip (List *a, List *b)
737 {
738 NickList *a1 = (NickList *)a, *b1 = (NickList *)b;
739 unsigned long at, bt;
740 if (!a1->ip && !b1->ip)
741 return -1;
742 /* return strcmp(a1->nick, b1->nick);*/
743 if (!a1->ip)
744 return -1;
745 if (!b1->ip)
746 return 1;
747 at = inet_addr(a1->ip); bt = inet_addr(b1->ip);
748 if (at < bt)
749 return 1;
750 if (at > bt)
751 return -1;
752 return strcmp(a1->nick, b1->nick);
753 }
754
755 /* Compare two Nicks by channel status, chanop > halfop > voice */
cmp_stat(List * a,List * b)756 int cmp_stat (List *a, List *b)
757 {
758 NickList *a1 = (NickList *)a, *b1 = (NickList *)b;
759 int a_status =
760 nick_isop(a1) ? 0 : nick_ishalfop(a1) ? 1 : nick_isvoice(a1) ? 2 : 3;
761 int b_status =
762 nick_isop(b1) ? 0 : nick_ishalfop(b1) ? 1 : nick_isvoice(b1) ? 2 : 3;
763 int cmp;
764
765 cmp = a_status - b_status;
766
767 /* Equal status */
768 if (cmp == 0)
769 cmp = strcmp(a1->nick, b1->nick);
770
771 return cmp;
772 }
773
774 /* Determines if the Nick matches the nick!user@host mask given. */
nick_match(NickList * nick,char * mask)775 int nick_match(NickList *nick, char *mask)
776 {
777 int match = 0;
778 char *nuh = m_3dup(nick->nick, "!", nick->host);
779
780 match = wild_match(mask, nuh);
781 new_free(&nuh);
782
783 return match;
784 }
785
BX_sorted_nicklist(ChannelList * chan,int sort)786 NickList *BX_sorted_nicklist(ChannelList *chan, int sort)
787 {
788 NickList *tmp, *l = NULL, *list = NULL, *last = NULL;
789 for (tmp = next_nicklist(chan, NULL); tmp; tmp = next_nicklist(chan, tmp))
790 {
791 l = (NickList *)new_malloc(sizeof(NickList));
792 memcpy(l, tmp, sizeof(NickList));
793 l->next = NULL;
794 switch(sort)
795 {
796 case NICKSORT_HOST:
797 add_to_list_ext((List **)&list, (List *)l, cmp_host);
798 break;
799 case NICKSORT_STAT:
800 add_to_list_ext((List **)&list, (List *)l, cmp_stat);
801 break;
802 case NICKSORT_TIME:
803 add_to_list_ext((List **)&list, (List *)l, cmp_time);
804 break;
805 case NICKSORT_IP:
806 add_to_list_ext((List **)&list, (List *)l, cmp_ip);
807 break;
808 case NICKSORT_NONE:
809 if (last)
810 last->next = l;
811 else
812 list = l;
813 break;
814 default:
815 case NICKSORT_NICK:
816 case NICKSORT_NORMAL:
817 add_to_list((List **)&list, (List *)l);
818 break;
819 }
820 last = l;
821 }
822 return list;
823 }
824
BX_clear_sorted_nicklist(NickList ** list)825 void BX_clear_sorted_nicklist(NickList **list)
826 {
827 register NickList *t;
828 while(*list)
829 {
830 t = (*list)->next;
831 new_free((char **)&(*list));
832 *list = t;
833 }
834 }
835
BX_add_name_to_floodlist(char * name,char * host,char * channel,HashEntry * list,unsigned int size)836 Flooding *BX_add_name_to_floodlist(char *name, char *host, char *channel, HashEntry *list, unsigned int size)
837 {
838 Flooding *nptr;
839 unsigned long hvalue = hash_nickname(name, size);
840 nptr = (Flooding *)new_malloc(sizeof(Flooding));
841 nptr->next = (Flooding *) list[hvalue].list;
842 nptr->name = m_strdup(name);
843 nptr->host = m_strdup(host);
844 list[hvalue].list = (void *) nptr;
845 /* quick tally of nicks in chain in this array spot */
846 list[hvalue].links++;
847 /* keep stats on hits to this array spot */
848 list[hvalue].hits++;
849 return nptr;
850 }
851
BX_find_name_in_floodlist(char * name,char * host,HashEntry * list,unsigned int size,int remove)852 Flooding *BX_find_name_in_floodlist(char *name, char *host, HashEntry *list, unsigned int size, int remove)
853 {
854 HashEntry *location;
855 register Flooding *tmp, *prev = NULL;
856 unsigned long hvalue = hash_nickname(name, size);
857
858 location = &(list[hvalue]);
859
860 /* at this point, we found the array spot, now search
861 * as regular linked list, or as ircd likes to say...
862 * "We found the bucket, now search the chain"
863 */
864 for (tmp = (Flooding *) location->list; tmp; prev = tmp, tmp = tmp->next)
865 {
866 if (!my_stricmp(name, tmp->name))
867 {
868 if (remove != REMOVE_FROM_LIST)
869 move_gen_link_to_top((List *)tmp, (List *)prev, location);
870 else
871 {
872 location->links--;
873 remove_gen_link_from_list((List *)tmp, (List *)prev, location);
874 }
875 return tmp;
876 }
877 }
878 return NULL;
879 }
880
881