-/* UserNode.c - NeonServ v5.2
- * Copyright (C) 2011 Philipp Kreil (pk910)
+/* UserNode.c - NeonServ v5.5
+ * Copyright (C) 2011-2012 Philipp Kreil (pk910)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "UserNode.h"
+#include "ChanNode.h"
#include "ChanUser.h"
#include "tools.h"
+#include "IRCEvents.h"
+#include "IPNode.h"
static struct UserNode **userList;
+unsigned int valid_user_modes[] = {
+ 1, 'o',
+ 2, 'O',
+ 3, 'i',
+ 4, 'w',
+ 5, 's',
+ 6, 'd',
+ 7, 'k',
+ 8, 'g',
+ 9, 'n',
+ 10, 'I',
+ 11, 'X',
+ 12, 'S',
+ 13, 'H',
+ 14, 'c',
+ 15, 'W',
+ 16, 't',
+ 17, 'D',
+ 18, 'x',
+// ^ maximum is 32!!!
+ 0x00, 0x00
+};
+
void init_UserNode() {
+ unsigned int *mode, flag = 1;
userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
+ for (mode = valid_user_modes; mode[1]; mode += 2) {
+ mode[0] = flag;
+ flag = flag << 1;
+ }
}
void free_UserNode() {
return -1; //ERROR!
}
+static unsigned int* getUserModeOptions(char mode) {
+ unsigned int *cmode;
+ for (cmode = valid_user_modes; cmode[1]; cmode += 2) {
+ if(cmode[1] == mode)
+ return cmode;
+ }
+ return NULL;
+}
+
+int isUserModeSet(struct UserNode *user, char modeChar) {
+ unsigned int *modeOpt = getUserModeOptions(modeChar);
+ return (user->usermode & modeOpt[0]);
+}
+
+void parseUserModes(struct UserNode* user, char *modeStr) {
+ int i, add = 1;
+ unsigned int *modeOpt;
+ for(i = 0; i < strlen(modeStr); i++) {
+ if(modeStr[i] == '+') {
+ add = 1;
+ continue;
+ }
+ if(modeStr[i] == '-') {
+ add = 0;
+ continue;
+ }
+ modeOpt = getUserModeOptions(modeStr[i]);
+ if(!modeOpt) continue; // unknown mode?
+ if(add) {
+ user->usermode |= modeOpt[0];
+ } else {
+ user->usermode &= ~modeOpt[0];
+ }
+ }
+}
+
+
struct UserNode* getUserByNick(const char *nick) { //case sensitive
int userListIndex = get_nicklist_entry(*nick);
if(userListIndex == -1 || userList[userListIndex] == NULL)
return NULL;
+ SYNCHRONIZE(cache_sync);
struct UserNode *user;
for(user = userList[userListIndex]; user; user = user->next) {
- if(!stricmp(nick, user->nick))
+ if(!stricmp(nick, user->nick)) {
+ DESYNCHRONIZE(cache_sync);
return user;
+ }
}
+ DESYNCHRONIZE(cache_sync);
return NULL;
}
struct UserNode* getUserByMask(const char *mask) { //case sensitive
+ SYNCHRONIZE(cache_sync);
char cmask[strlen(mask)+1];
strcpy(cmask, mask);
int i;
if(cmask[i] == '!') {
cmask[i] = 0;
user = getUserByNick(&cmask[0]);
+ DESYNCHRONIZE(cache_sync);
return user;
} else if(cmask[i] == '.') {
//it's a server
+ DESYNCHRONIZE(cache_sync);
return NULL;
}
}
+ DESYNCHRONIZE(cache_sync);
return NULL;
}
if(!isalpha(*nick))
return getUserByNick(nick);
+ SYNCHRONIZE(cache_sync);
int userListIndex;
struct UserNode *user;
userListIndex = get_nicklist_entry(tolower(*nick));
if(userListIndex != -1 && userList[userListIndex] != NULL) {
for(user = userList[userListIndex]; user; user = user->next) {
- if(!stricmp(nick, user->nick))
+ if(!stricmp(nick, user->nick)) {
+ DESYNCHRONIZE(cache_sync);
return user;
+ }
}
}
//search in the upper case "section"
userListIndex = get_nicklist_entry(toupper(*nick));
if(userListIndex != -1 && userList[userListIndex] != NULL) {
for(user = userList[userListIndex]; user; user = user->next) {
- if(!stricmp(nick, user->nick))
+ if(!stricmp(nick, user->nick)) {
+ DESYNCHRONIZE(cache_sync);
return user;
+ }
}
}
+ DESYNCHRONIZE(cache_sync);
return NULL;
}
int countUsersWithHost(char *host) {
+ SYNCHRONIZE(cache_sync);
int i, count = 0;
struct UserNode *user;
- for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+ for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
for(user = userList[i]; user; user = user->next) {
if(!strcmp(user->host, host)) {
count++;
}
}
}
+ DESYNCHRONIZE(cache_sync);
return count;
}
char *getAuthFakehost(char *auth) {
+ SYNCHRONIZE(cache_sync);
int i;
struct UserNode *user;
- for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+ for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
for(user = userList[i]; user; user = user->next) {
if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
+ DESYNCHRONIZE(cache_sync);
return user->host;
}
}
}
+ DESYNCHRONIZE(cache_sync);
return NULL;
}
struct UserNode* getAllUsers(struct UserNode *last) {
+ SYNCHRONIZE(cache_sync);
if(last == NULL || last->next == NULL) {
int cindex;
if(last == NULL)
cindex = 0;
else
cindex = get_nicklist_entry(last->nick[0]) + 1;
- while(userList[cindex] == NULL && cindex <= VALID_NICK_CHARS_FIRST_LEN)
+ while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
cindex++;
- if(cindex > VALID_NICK_CHARS_FIRST_LEN) return NULL;
+ DESYNCHRONIZE(cache_sync);
+ if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
return userList[cindex];
- } else
+ } else {
+ DESYNCHRONIZE(cache_sync);
return last->next;
+ }
+}
+
+struct UserNode* getUsersWithAuth(const char *auth, struct UserNode *last) {
+ SYNCHRONIZE(cache_sync);
+ int cindex = (last ? get_nicklist_entry(last->nick[0]) : 0);
+ struct UserNode *cuser = last;
+ while(cindex <= VALID_NICK_CHARS_FIRST_LEN) {
+ for(cuser = (cuser ? cuser->next : userList[cindex]); cuser; cuser = cuser->next) {
+ if((cuser->flags & USERFLAG_ISAUTHED) && !strcmp(cuser->auth, auth)) {
+ DESYNCHRONIZE(cache_sync);
+ return cuser;
+ }
+ }
+ cindex++;
+ cuser = NULL;
+ }
+ DESYNCHRONIZE(cache_sync);
+ return NULL;
}
int getUserCount() {
+ SYNCHRONIZE(cache_sync);
int i, count = 0;
struct UserNode *user;
- for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
+ for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
for(user = userList[i]; user; user = user->next) {
count++;
}
}
+ DESYNCHRONIZE(cache_sync);
return count;
}
user->created = time(0);
user->ident[0] = 0;
user->host[0] = 0;
+ user->ip = NULL;
user->realname[0] = 0;
user->flags = 0;
user->channel = NULL;
user->last_who = 0;
+ user->usermode = 0;
+ SYNCHRONIZE(cache_sync);
user->next = userList[userListIndex];
userList[userListIndex] = user;
+ DESYNCHRONIZE(cache_sync);
return user;
}
return user;
}
-struct UserNode* createTempUser(const char *mask) {
+struct UserNode* createTempUser(const char *nick) {
+ int already_on_list = 0;
+ struct UserNode *user = NULL;
+ if(!is_valid_nick(nick)) {
+ return NULL;
+ }
+ for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
+ if(!stricmp(user->nick, nick)) {
+ already_on_list = 1;
+ break;
+ }
+ }
+ if(!user) {
+ user = malloc(sizeof(*user));
+ if (!user) {
+ perror("malloc() failed");
+ return NULL;
+ }
+ user->ident[0] = 0;
+ user->host[0] = 0;
+ user->ip = NULL;
+ user->realname[0] = 0;
+ user->flags = 0;
+ user->channel = NULL;
+ user->usermode = 0;
+ user->last_who = 0;
+ } else
+ user->flags &= ~USERFLAG_FREETMPUSER;
+ user->created = time(0);
+ if(user->created - user->last_who > REWHO_TIMEOUT)
+ user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
+ strcpy(user->nick, nick);
+ if(!already_on_list) {
+ SYNCHRONIZE(cache_sync);
+ user->next = userList[TEMPUSER_LIST_INDEX];
+ userList[TEMPUSER_LIST_INDEX] = user;
+ DESYNCHRONIZE(cache_sync);
+ }
+ return user;
+}
+
+struct UserNode* createTempUserMask(const char *mask) {
//note: it could also be a server we have to create a temponary user for...
char cmask[strlen(mask)+1];
strcpy(cmask, mask);
int i, ii = 0;
+ int already_on_list = 0;
struct UserNode *user = NULL;
for(i = 0; i < strlen(mask)+1; i++) {
if(cmask[i] == '!') {
cmask[i] = 0;
- user = malloc(sizeof(*user));
- if (!user)
- {
- perror("malloc() failed");
+ if(!is_valid_nick(cmask)) {
return NULL;
}
- strcpy(user->nick, cmask);
+ for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
+ if(!stricmp(user->nick, cmask)) {
+ already_on_list = 1;
+ break;
+ }
+ }
+ if(!user) {
+ user = malloc(sizeof(*user));
+ if (!user) {
+ perror("malloc() failed");
+ return NULL;
+ }
+ user->ident[0] = 0;
+ user->host[0] = 0;
+ user->ip = NULL;
+ user->realname[0] = 0;
+ user->flags = 0;
+ user->channel = NULL;
+ user->usermode = 0;
+ user->last_who = 0;
+ } else
+ user->flags &= ~USERFLAG_FREETMPUSER;
user->created = time(0);
- user->ident[0] = 0;
- user->host[0] = 0;
- user->realname[0] = 0;
- user->flags = 0;
- user->channel = NULL;
- user->last_who = 0;
+ if(user->created - user->last_who > REWHO_TIMEOUT)
+ user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
+ strcpy(user->nick, cmask);
ii = i+1;
} else if(cmask[i] == '.' && !user) {
//it's a server
return NULL;
}
strcpy(user->host, cmask);
+ strncpy(user->nick, cmask, NICKLEN);
+ user->nick[NICKLEN] = 0;
user->created = time(0);
user->ident[0] = 0;
user->host[0] = 0;
+ user->ip = NULL;
user->realname[0] = 0;
user->flags = USERFLAG_ISSERVER;
user->channel = NULL;
+ user->usermode = 0;
user->last_who = 0;
- return user;
+ break;
} else if(cmask[i] == '@') {
if(user == NULL) return NULL;
cmask[i] = 0;
user->created = time(0);
user->ident[0] = 0;
user->host[0] = 0;
+ user->ip = NULL;
user->realname[0] = 0;
user->flags = 0;
user->channel = NULL;
+ user->usermode = 0;
user->last_who = 0;
- return user;
+ break;
}
strcpy(user->host, &cmask[ii]);
}
}
+ if(!already_on_list) {
+ SYNCHRONIZE(cache_sync);
+ user->next = userList[TEMPUSER_LIST_INDEX];
+ userList[TEMPUSER_LIST_INDEX] = user;
+ DESYNCHRONIZE(cache_sync);
+ }
return user;
}
}
//delUser(user, 0); //EPIC FAIL! This deletes the user from the channel Userlist -.-
//manually remove the user from the old userList
+ SYNCHRONIZE(cache_sync);
int userListIndex = get_nicklist_entry(user->nick[0]);
if(userListIndex != -1) {
struct UserNode *cuser, *last_user = NULL;
strcpy(user->nick, new_nick);
user->next = userList[userListIndex];
userList[userListIndex] = user;
+ DESYNCHRONIZE(cache_sync);
return 1;
}
void delUser(struct UserNode* user, int freeUser) {
- int userListIndex = get_nicklist_entry(user->nick[0]);
+ int userListIndex = ((user->flags & USERFLAG_ISTMPUSER) ? TEMPUSER_LIST_INDEX : get_nicklist_entry(user->nick[0]));
if(userListIndex == -1) return;
+ SYNCHRONIZE(cache_sync);
+ event_freeuser(user);
struct UserNode *cuser, *last_user = NULL;
for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
if(cuser == user) {
} else
last_user = cuser;
}
+ if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
+ user->flags |= USERFLAG_FREE_AFTER_WHO;
+ freeUser = 0;
+ }
if(user->channel) {
struct ChanUser *chanUser, *next;
for(chanUser = user->channel; chanUser; chanUser = next) {
removeChanUserFromLists(chanUser, 1, 0, freeUser);
}
}
- if(freeUser)
+ if(freeUser) {
+ if(user->ip)
+ freeIPNode(user->ip);
free(user);
- else
+ } else
user->next = NULL;
+ DESYNCHRONIZE(cache_sync);
}
void clearTempUsers() {
+ SYNCHRONIZE(cache_sync);
int userListIndex = TEMPUSER_LIST_INDEX;
- struct UserNode *cuser, *last_user = NULL, *next;
+ struct UserNode *cuser, *next;
time_t now = time(0);
for(cuser = userList[userListIndex]; cuser; cuser = next) {
next = cuser->next;
if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
- if(last_user)
- last_user->next = cuser->next;
- else
- userList[userListIndex] = cuser->next;
- break;
- } else
- last_user = cuser;
+ delUser(cuser, 1);
+ }
}
+ DESYNCHRONIZE(cache_sync);
}