#include "irc.h" static char cvsrevision[] = "$Id: user.c,v 1.1.1.1 2003/04/11 01:09:07 dan Exp $"; CVS_REVISION(user_c) #include "struct.h" #include "ircaux.h" #include "list.h" #include "hash.h" #include "struct.h" #include "userlist.h" #include "misc.h" #include "output.h" #define MAIN_SOURCE #include "modval.h" #define USERHOST_HASHSIZE 501 #define USERCHAN_HASHSIZE 20 #ifdef WANT_USERLIST HashEntry UserListByHost_Table[USERHOST_HASHSIZE]; HashEntry UserListByChannel_Table[USERCHAN_HASHSIZE]; UserList *user_list = NULL; static long hash_name(char *str, unsigned int size) { const unsigned char *p = (const unsigned char *)str; unsigned long g, hash = 0; if (!p) return -1; while (*p) { if (*p == '*' || *p =='?' || *p == ',') return -1; hash = (hash << 4) + ((*p >= 'A' && *p <= 'Z') ? (*p+32) : *p); if ((g = hash & 0xF0000000)) hash ^= g >> 24; hash &= ~g; p++; } return (hash % size); } /* userlist entry can be put into our tier 1 */ static inline void add_userlist_to_tier_1(UserList *ptr, unsigned long hvalue) { ptr->next = (UserList *) UserListByHost_Table[hvalue].list; /* assign our new linked list into array spot */ UserListByHost_Table[hvalue].list = (void *) ptr; /* quick tally of userlists in chain in this array spot */ UserListByHost_Table[hvalue].links++; } static inline void add_userlist_to_tier_2(UserList *ptr, unsigned long hvalue) { ptr->next = (UserList *) UserListByChannel_Table[hvalue].list; /* assign our new linked list into array spot */ UserListByChannel_Table[hvalue].list = (void *) ptr; /* quick tally of userlists in chain in this array spot */ UserListByChannel_Table[hvalue].links++; } static inline void add_userlist_to_tier_3(UserList *uptr) { add_to_list((List **)&user_list, (List *)uptr); } void add_userlist(UserList *uptr) { char *ptr; long hvalue; if (!(ptr = strrchr(uptr->host, '@'))) { add_userlist_to_tier_3(uptr); return; } if ((hvalue = hash_name(ptr, USERHOST_HASHSIZE)) != -1) { add_userlist_to_tier_1(uptr, hvalue); return; } #if 0 if (!strchr(uptr->channels, '*')) { char *channel, *ptr; channel = alloca(strlen(uptr->channels)+1); strcpy(channel, uptr->channels); while ((ptr = next_in_comma_list(channel, &channel))) { if (!*ptr) return; hvalue = hash_name(ptr, USERCHAN_HASHSIZE); add_userlist_to_tier_2(uptr, hvalue); if (channel && *channel) { UserList *newptr; newptr = new_malloc(sizeof(UserList)); memcpy(newptr, uptr, sizeof(UserList)); uptr = newptr; } } } #else if ((hvalue = hash_name(uptr->channels, USERCHAN_HASHSIZE)) != -1) { add_userlist_to_tier_2(uptr, hvalue); return; } #endif add_userlist_to_tier_3(uptr); } /* * move_link_to_top: used by find routine, brings link * to the top of the list in the specific array location */ static inline void move_link_to_top(UserList *tmp, UserList *prev, HashEntry *location) { if (prev) { UserList *old_list; old_list = (UserList *) location->list; location->list = (void *) tmp; prev->next = tmp->next; tmp->next = old_list; } } /* * remove_link_from_list: used by find routine, removes link * from our chain of hashed entries. */ static inline void remove_link_from_list(UserList *tmp, UserList *prev, HashEntry *location) { if (prev) { /* remove the link from the middle of the list */ prev->next = tmp->next; } else { /* unlink the first link, and connect next one up */ location->list = (void *) tmp->next; } /* set tmp's next to NULL, as its unlinked now */ tmp->next = NULL; } static inline UserList *find_userlist_tier3(char *host, char *channel, int remove) { register UserList *tmp; for (tmp = user_list; tmp; tmp = tmp->next) { if (wild_match(tmp->host, host) || !my_stricmp(tmp->host, host)) { if (check_channel_match(tmp->channels, channel) || !strcmp(tmp->channels, channel)) { if (remove) tmp = (UserList *)remove_from_list((List **)&user_list, tmp->nick); return tmp; } } } return NULL; } static inline UserList *find_userlist_tier1(char *userhost, char *channel, unsigned long hvalue, int remove) { HashEntry *location; register UserList *tmp, *prev = NULL; location = &UserListByHost_Table[hvalue]; for (tmp = (UserList *)location->list; tmp; prev = tmp, tmp = tmp->next) { if ((wild_match(tmp->host, userhost) ||!my_stricmp(tmp->host, userhost)) && check_channel_match(tmp->channels, channel)) { if (remove) { location->links--; remove_link_from_list(tmp, prev, location); } else move_link_to_top(tmp, prev, location); location->hits++; return tmp; } } return NULL; } static inline UserList *find_userlist_tier2(char *userhost,unsigned long hvalue, int remove) { HashEntry *location; register UserList *tmp, *prev = NULL; location = &UserListByChannel_Table[hvalue]; for (tmp = (UserList *)location->list; tmp; prev = tmp, tmp = tmp->next) { if (wild_match(tmp->host, userhost) || !my_stricmp(tmp->host, userhost)) { if (remove) { location->links--; remove_link_from_list(tmp, prev, location); } else move_link_to_top(tmp, prev, location); location->hits++; return tmp; } } return NULL; } UserList *find_userlist(char *userhost, char *channel, int remove) { char *ptr; long hvalue; /*char *host = clear_server_flags(userhost);*/ char *host = userhost; if (!(ptr = strrchr(userhost, '@'))) return find_userlist_tier3(host, channel, remove); if ((hvalue = hash_name(ptr, USERHOST_HASHSIZE)) != -1) { UserList *tmp; if ((tmp = find_userlist_tier1(host, channel, hvalue, remove))) return tmp; } if ((hvalue = hash_name(channel, USERCHAN_HASHSIZE)) != -1) { UserList *tmp; if ((tmp = find_userlist_tier2(host, hvalue, remove))) return tmp; } /* if we got here this is shitty */ return find_userlist_tier3(host, channel, remove); } UserList *create_sorted_userlist(void) { UserList *tmp = NULL, *t, *new; int i; for (i = 0; i < USERHOST_HASHSIZE; i++) { t = (UserList *)UserListByHost_Table[i].list; while (t) { new = new_malloc(sizeof(UserList)); memcpy(new, t, sizeof(UserList)); add_to_list((List **)&tmp, (List *)new); t = t->next; } } for (i = 0; i < USERCHAN_HASHSIZE; i++) { t = (UserList *)UserListByChannel_Table[i].list; while (t) { new = new_malloc(sizeof(UserList)); memcpy(new, t, sizeof(UserList)); add_to_list((List **)&tmp, (List *)new); t = t->next; } } for (t = user_list; t; t = t->next) { new = new_malloc(sizeof(UserList)); memcpy(new, t, sizeof(UserList)); add_to_list((List **)&tmp, (List *)new); } return tmp; } void destroy_sorted_userlist(UserList **uptr) { UserList *t; if (!uptr || !*uptr) return; while (*uptr) { t = (*uptr)->next; new_free(uptr); *uptr = t; } } #if 0 UserHist *next_userlist(UserList *uptr, int *size) { long hvalue = -1; static HashEntry *location = NULL; if (!uptr) { location = &UserListByHost_Table[0]; *size = USERHOST_HASHSIZE; hvalue = 0; while(((UserList *)location[hvalue].list) == NULL) { hvalue++; if (hvalue == USERHOST_HASHSIZE && *size == USERHOST_HASHSIZE) { location = &UserListByChannel_Table[0]; hvalue = 0; *size = USERCHAN_HASHSIZE; } else if (hvalue == USERCHAN_HASHSIZE && *size == USERCHAN_HASHSIZE) { hvalue = -1; break; } } if (hvalue != -1 && location[hvalue].list != NULL) return ((UserHist *)location[hvalue].list); location = NULL; *size = -1; return (user_list); } if (uptr->next) return uptr->next; else if (location && !uptr->next) { if (*size > -1 && location) { if (*size == USERHOST_HASHSIZE) hvalue = hash_name(strrchr(uptr->host, '@'), *size); else if (*size == USERCHAN_HASHSIZE) hvalue = hash_name(uptr->channels, *size); if (hvalue == -1) { location = NULL; *size = -1; return user_list; } hvalue++; if (*size == USERHOST_HASHSIZE && hvalue >= USERHOST_HASHSIZE) { /* end of current list */ location = &UserListByChannel_Table[0]; *size = USERCHAN_HASHSIZE; } while (((UserList *)location[hvalue].list) == NULL) { hvalue++; if (hvalue >= USERHOST_HASHSIZE) { location = &UserListByChannel_Table[0]; hvalue = 0; *size = USERCHAN_HASHSIZE; } else if (*size == USERCHAN_HASHSIZE && hvalue == USERCHAN_HASHSIZE) break; } if (location[hvalue].list != NULL) return ((UserList *)location[hvalue].list); location = NULL; *size = -1; return user_list; } } return NULL; } #endif static inline int check_best_passwd(char *passwd, char *test) { if (passwd && test) return !checkpass(test, passwd) ? 1 : 0; /* return !strcmp(passwd, test) ? 1 : 0;*/ return 0; } UserList *find_bestmatch(char *nick, char *userhost, char *channel, char *passwd) { UserList *best = NULL; UserList *best_passwd = NULL; register UserList *tmp; long hvalue = 0; int best_user_match = 0, best_chan_match = 0; int chan_match, user_match, passwd_match = 0; char *check; /*check = clear_server_flags(userhost);*/ check = userhost; if ((hvalue = hash_name(strrchr(check, '@'), USERHOST_HASHSIZE)) != -1) { for (tmp = (UserList *)UserListByHost_Table[hvalue].list; tmp; tmp = tmp->next) { user_match = wild_match(tmp->host, check); chan_match = check_channel_match(tmp->channels, channel); if (user_match > best_user_match && chan_match > best_chan_match) { best_chan_match = chan_match; best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } else if (best_user_match && user_match == best_user_match) { if (chan_match > best_chan_match) { best_chan_match = chan_match; best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } } } } if ((hvalue = hash_name(channel, USERCHAN_HASHSIZE)) != -1) { for (tmp = (UserList *)UserListByChannel_Table[hvalue].list; tmp; tmp = tmp->next) { user_match = wild_match(tmp->host, check); if (user_match > best_user_match) { best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } } } else if (hvalue == -1) { for (hvalue = 0; hvalue < USERCHAN_HASHSIZE; hvalue++) { for (tmp = (UserList *)UserListByChannel_Table[hvalue].list; tmp; tmp = tmp->next) { user_match = wild_match(tmp->host, check); chan_match = check_channel_match(tmp->channels, channel); if (user_match > best_user_match && chan_match > best_chan_match) { best_user_match = user_match; best_chan_match = chan_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } else if (best_user_match && user_match == best_user_match) { if (chan_match > best_chan_match) { best_chan_match = chan_match; best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } } } } } for (tmp = user_list; tmp; tmp = tmp->next) { if ((chan_match = check_channel_match(tmp->channels, channel)) > 0) { user_match = wild_match(tmp->host, check); if (user_match > best_user_match && chan_match > best_chan_match) { best_chan_match = chan_match; best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } else if (best_user_match && user_match == best_user_match) { if (chan_match > best_chan_match) { best_chan_match = chan_match; best_user_match = user_match; best = tmp; if ((passwd_match = check_best_passwd(tmp->password, passwd))) best_passwd = tmp; } } } } if (passwd) { if (!best_passwd) return NULL; else if (best_passwd) return best_passwd; } return best; } BUILT_IN_COMMAND(debug_user) { HashEntry *location; UserList *user; int i; int tier1 = 0, tier2 = 0, tier3 = 0; for (i = 0; i < USERHOST_HASHSIZE; i++) { user = (UserList *)UserListByHost_Table[i].list; location = &UserListByHost_Table[i]; while (user) { tier1++; put_it("Tier1[%d] %d %d %s %s", i, location->links, location->hits, user->host, user->channels); user = user->next; } } for (i = 0; i < USERCHAN_HASHSIZE; i++) { user = (UserList *)UserListByChannel_Table[i].list; location = &UserListByChannel_Table[i]; while (user) { tier2++; put_it("Tier2[%d] %d %d %s %s", i, location->links, location->hits, user->host, user->channels); user = user->next; } } for (tier3 = 0, user = user_list; user; user = user->next, tier3++) put_it("Tier3[%d] %s %s", tier3, user->host, user->channels); put_it("Tier1 = [%d] Tier2 = [%d] Tier3 = [%d]", tier1, tier2, tier3); } UserList *next_userlist(UserList *uptr, int *size, void **location) { unsigned long hvalue = -1; /* we start iterating the list will a null pointer */ if (!uptr) { *location = &UserListByHost_Table[0]; *size = USERHOST_HASHSIZE; hvalue = 0; while(((UserList *)((HashEntry*)*location)[hvalue].list) == NULL) { hvalue++; if (hvalue == USERHOST_HASHSIZE && *size == USERHOST_HASHSIZE) { *location = &UserListByChannel_Table[0]; hvalue = 0; *size = USERCHAN_HASHSIZE; } else if (hvalue == USERCHAN_HASHSIZE && *size == USERCHAN_HASHSIZE) { hvalue = -1; break; } } if (hvalue != -1 && ((HashEntry *)*location)[hvalue].list != NULL) return ((UserList *)((HashEntry *)*location)[hvalue].list); *location = NULL; *size = -1; return (user_list); } else if (uptr->next) return uptr->next; else if (*location) { if (*size > -1) { if (*size == USERHOST_HASHSIZE) hvalue = hash_name(strrchr(uptr->host, '@'), *size); else if (*size == USERCHAN_HASHSIZE) hvalue = hash_name(uptr->channels, *size); if (hvalue == -1) { *location = NULL; *size = -1; return user_list; } hvalue++; if (*size == USERHOST_HASHSIZE && hvalue >= USERHOST_HASHSIZE) { /* end of current list */ *location = &UserListByChannel_Table[0]; *size = USERCHAN_HASHSIZE; } while (((UserList *)((HashEntry *)*location)[hvalue].list) == NULL) { hvalue++; if (hvalue >= USERHOST_HASHSIZE) { *location = &UserListByChannel_Table[0]; hvalue = 0; *size = USERCHAN_HASHSIZE; } else if (*size == USERCHAN_HASHSIZE && hvalue >= USERCHAN_HASHSIZE) { hvalue = -1; break; } } if (hvalue != -1 && ((HashEntry *)*location)[hvalue].list != NULL) return ((UserList *)((HashEntry *)*location)[hvalue].list); *location = NULL; *size = -1; return user_list; } } return NULL; } #endif