Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/hash.c
1069 views
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 $";
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
*/
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
*/
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
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
*/
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
*/
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
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
*/
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
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
*/
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
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
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
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
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
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
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
*/
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
*/
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
*/
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
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
*/
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
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
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
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
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
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
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 */
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. */
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
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
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
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
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
882