1 /* UserNode.c - NeonServ v5.5
2 * Copyright (C) 2011-2012 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "IRCEvents.h"
24 static struct UserNode **userList;
26 unsigned int valid_user_modes[] = {
49 void init_UserNode() {
50 unsigned int *mode, flag = 1;
51 userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
52 for (mode = valid_user_modes; mode[1]; mode += 2) {
58 void free_UserNode() {
59 //kamikaze free all users
60 //chanusers will be destroyed in free_ChanNode()
62 struct UserNode *user, *next;
63 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
64 for(user = userList[i]; user; user = next) {
72 int is_valid_nick(const char *nick) {
74 //first char must be one of: a-zA-Z{|}~[\]^_`
75 if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
77 //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
78 for (i = 0; nick[i]; ++i)
79 if (!strchr(VALID_NICK_CHARS, nick[i]))
81 if (strlen(nick) > NICKLEN)
86 static int get_nicklist_entry(int nick) {
88 char *valid_chars = VALID_NICK_CHARS_FIRST;
89 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
90 if(valid_chars[i] == nick)
96 static unsigned int* getUserModeOptions(char mode) {
98 for (cmode = valid_user_modes; cmode[1]; cmode += 2) {
105 int isUserModeSet(struct UserNode *user, char modeChar) {
106 unsigned int *modeOpt = getUserModeOptions(modeChar);
107 return (user->usermode & modeOpt[0]);
110 void parseUserModes(struct UserNode* user, char *modeStr) {
112 unsigned int *modeOpt;
113 for(i = 0; i < strlen(modeStr); i++) {
114 if(modeStr[i] == '+') {
118 if(modeStr[i] == '-') {
122 modeOpt = getUserModeOptions(modeStr[i]);
123 if(!modeOpt) continue; // unknown mode?
125 user->usermode |= modeOpt[0];
127 user->usermode &= ~modeOpt[0];
133 struct UserNode* getUserByNick(const char *nick) { //case sensitive
134 int userListIndex = get_nicklist_entry(*nick);
135 if(userListIndex == -1 || userList[userListIndex] == NULL)
137 SYNCHRONIZE(cache_sync);
138 struct UserNode *user;
139 for(user = userList[userListIndex]; user; user = user->next) {
140 if(!stricmp(nick, user->nick)) {
141 DESYNCHRONIZE(cache_sync);
145 DESYNCHRONIZE(cache_sync);
149 struct UserNode* getUserByMask(const char *mask) { //case sensitive
150 SYNCHRONIZE(cache_sync);
151 char cmask[strlen(mask)+1];
154 struct UserNode *user = NULL;
155 for(i = 0; i < strlen(mask); i++) {
156 if(cmask[i] == '!') {
158 user = getUserByNick(&cmask[0]);
159 DESYNCHRONIZE(cache_sync);
161 } else if(cmask[i] == '.') {
163 DESYNCHRONIZE(cache_sync);
167 DESYNCHRONIZE(cache_sync);
171 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
173 return getUserByNick(nick);
175 SYNCHRONIZE(cache_sync);
177 struct UserNode *user;
179 //search in the lower case "section"
180 userListIndex = get_nicklist_entry(tolower(*nick));
181 if(userListIndex != -1 && userList[userListIndex] != NULL) {
182 for(user = userList[userListIndex]; user; user = user->next) {
183 if(!stricmp(nick, user->nick)) {
184 DESYNCHRONIZE(cache_sync);
189 //search in the upper case "section"
190 userListIndex = get_nicklist_entry(toupper(*nick));
191 if(userListIndex != -1 && userList[userListIndex] != NULL) {
192 for(user = userList[userListIndex]; user; user = user->next) {
193 if(!stricmp(nick, user->nick)) {
194 DESYNCHRONIZE(cache_sync);
199 DESYNCHRONIZE(cache_sync);
203 int countUsersWithHost(char *host) {
204 SYNCHRONIZE(cache_sync);
206 struct UserNode *user;
207 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
208 for(user = userList[i]; user; user = user->next) {
209 if(!strcmp(user->host, host)) {
214 DESYNCHRONIZE(cache_sync);
218 char *getAuthFakehost(char *auth) {
219 SYNCHRONIZE(cache_sync);
221 struct UserNode *user;
222 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
223 for(user = userList[i]; user; user = user->next) {
224 if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
225 DESYNCHRONIZE(cache_sync);
230 DESYNCHRONIZE(cache_sync);
234 struct UserNode* getAllUsers(struct UserNode *last) {
235 SYNCHRONIZE(cache_sync);
236 if(last == NULL || last->next == NULL) {
241 cindex = get_nicklist_entry(last->nick[0]) + 1;
242 while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
244 DESYNCHRONIZE(cache_sync);
245 if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
246 return userList[cindex];
248 DESYNCHRONIZE(cache_sync);
253 struct UserNode* getUsersWithAuth(const char *auth, struct UserNode *last) {
254 SYNCHRONIZE(cache_sync);
255 int cindex = (last ? get_nicklist_entry(last->nick[0]) : 0);
256 struct UserNode *cuser = last;
257 while(cindex <= VALID_NICK_CHARS_FIRST_LEN) {
258 for(cuser = (cuser ? cuser->next : userList[cindex]); cuser; cuser = cuser->next) {
259 if((cuser->flags & USERFLAG_ISAUTHED) && !strcmp(cuser->auth, auth)) {
260 DESYNCHRONIZE(cache_sync);
267 DESYNCHRONIZE(cache_sync);
272 SYNCHRONIZE(cache_sync);
274 struct UserNode *user;
275 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
276 for(user = userList[i]; user; user = user->next) {
280 DESYNCHRONIZE(cache_sync);
284 struct UserNode* addUser(const char *nick) {
285 int userListIndex = get_nicklist_entry(*nick);
286 if(userListIndex == -1 || !is_valid_nick(nick))
288 struct UserNode *user = malloc(sizeof(*user));
291 perror("malloc() failed");
294 strcpy(user->nick, nick);
295 user->created = time(0);
299 user->realname[0] = 0;
301 user->channel = NULL;
304 SYNCHRONIZE(cache_sync);
305 user->next = userList[userListIndex];
306 userList[userListIndex] = user;
307 DESYNCHRONIZE(cache_sync);
311 struct UserNode* addUserMask(const char *mask) {
312 char cmask[strlen(mask)+1];
315 struct UserNode *user = NULL;
316 for(i = 0; i < strlen(mask)+1; i++) {
317 if(cmask[i] == '!') {
319 user = addUser(cmask);
320 if(user == NULL) return NULL;
322 } else if(cmask[i] == '.' && !user) {
325 } else if(cmask[i] == '@') {
326 if(user == NULL) return NULL;
328 strcpy(user->ident, &cmask[ii]);
330 } else if(cmask[i] == '\0') {
331 if(user == NULL) return NULL;
332 strcpy(user->host, &cmask[ii]);
338 struct UserNode* createTempUser(const char *nick) {
339 int already_on_list = 0;
340 struct UserNode *user = NULL;
341 if(!is_valid_nick(nick)) {
344 for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
345 if(!stricmp(user->nick, nick)) {
351 user = malloc(sizeof(*user));
353 perror("malloc() failed");
359 user->realname[0] = 0;
361 user->channel = NULL;
365 user->flags &= ~USERFLAG_FREETMPUSER;
366 user->created = time(0);
367 if(user->created - user->last_who > REWHO_TIMEOUT)
368 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
369 strcpy(user->nick, nick);
370 if(!already_on_list) {
371 SYNCHRONIZE(cache_sync);
372 user->next = userList[TEMPUSER_LIST_INDEX];
373 userList[TEMPUSER_LIST_INDEX] = user;
374 DESYNCHRONIZE(cache_sync);
379 struct UserNode* createTempUserMask(const char *mask) {
380 //note: it could also be a server we have to create a temponary user for...
381 char cmask[strlen(mask)+1];
384 int already_on_list = 0;
385 struct UserNode *user = NULL;
386 for(i = 0; i < strlen(mask)+1; i++) {
387 if(cmask[i] == '!') {
389 if(!is_valid_nick(cmask)) {
392 for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
393 if(!stricmp(user->nick, cmask)) {
399 user = malloc(sizeof(*user));
401 perror("malloc() failed");
407 user->realname[0] = 0;
409 user->channel = NULL;
413 user->flags &= ~USERFLAG_FREETMPUSER;
414 user->created = time(0);
415 if(user->created - user->last_who > REWHO_TIMEOUT)
416 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
417 strcpy(user->nick, cmask);
419 } else if(cmask[i] == '.' && !user) {
421 user = malloc(sizeof(*user));
424 perror("malloc() failed");
427 strcpy(user->host, cmask);
428 strncpy(user->nick, cmask, NICKLEN);
429 user->nick[NICKLEN] = 0;
430 user->created = time(0);
434 user->realname[0] = 0;
435 user->flags = USERFLAG_ISSERVER;
436 user->channel = NULL;
440 } else if(cmask[i] == '@') {
441 if(user == NULL) return NULL;
443 strcpy(user->ident, &cmask[ii]);
445 } else if(cmask[i] == '\0') {
448 user = malloc(sizeof(*user));
451 perror("malloc() failed");
454 strcpy(user->nick, cmask);
455 user->created = time(0);
459 user->realname[0] = 0;
461 user->channel = NULL;
466 strcpy(user->host, &cmask[ii]);
469 if(!already_on_list) {
470 SYNCHRONIZE(cache_sync);
471 user->next = userList[TEMPUSER_LIST_INDEX];
472 userList[TEMPUSER_LIST_INDEX] = user;
473 DESYNCHRONIZE(cache_sync);
478 int renameUser(struct UserNode* user, const char *new_nick) {
479 if(!is_valid_nick(new_nick))
481 if(user->nick[0] == *new_nick) {
482 strcpy(user->nick, new_nick);
485 //delUser(user, 0); //EPIC FAIL! This deletes the user from the channel Userlist -.-
486 //manually remove the user from the old userList
487 SYNCHRONIZE(cache_sync);
488 int userListIndex = get_nicklist_entry(user->nick[0]);
489 if(userListIndex != -1) {
490 struct UserNode *cuser, *last_user = NULL;
491 for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
494 last_user->next = user->next;
496 userList[userListIndex] = user->next;
502 userListIndex = get_nicklist_entry(*new_nick);
503 strcpy(user->nick, new_nick);
504 user->next = userList[userListIndex];
505 userList[userListIndex] = user;
506 DESYNCHRONIZE(cache_sync);
510 void delUser(struct UserNode* user, int freeUser) {
511 int userListIndex = ((user->flags & USERFLAG_ISTMPUSER) ? TEMPUSER_LIST_INDEX : get_nicklist_entry(user->nick[0]));
512 if(userListIndex == -1) return;
513 SYNCHRONIZE(cache_sync);
514 event_freeuser(user);
515 struct UserNode *cuser, *last_user = NULL;
516 for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
519 last_user->next = user->next;
521 userList[userListIndex] = user->next;
526 if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
527 user->flags |= USERFLAG_FREE_AFTER_WHO;
531 struct ChanUser *chanUser, *next;
532 for(chanUser = user->channel; chanUser; chanUser = next) {
533 next = chanUser->next_chan;
534 removeChanUserFromLists(chanUser, 1, 0, freeUser);
539 freeIPNode(user->ip);
543 DESYNCHRONIZE(cache_sync);
546 void clearTempUsers() {
547 SYNCHRONIZE(cache_sync);
548 int userListIndex = TEMPUSER_LIST_INDEX;
549 struct UserNode *cuser, *next;
550 time_t now = time(0);
551 for(cuser = userList[userListIndex]; cuser; cuser = next) {
553 if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
557 DESYNCHRONIZE(cache_sync);