1 /* UserNode.c - NeonServ v5.4
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 void init_UserNode() {
27 userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
30 void free_UserNode() {
31 //kamikaze free all users
32 //chanusers will be destroyed in free_ChanNode()
34 struct UserNode *user, *next;
35 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
36 for(user = userList[i]; user; user = next) {
44 int is_valid_nick(const char *nick) {
46 //first char must be one of: a-zA-Z{|}~[\]^_`
47 if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
49 //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
50 for (i = 0; nick[i]; ++i)
51 if (!strchr(VALID_NICK_CHARS, nick[i]))
53 if (strlen(nick) > NICKLEN)
58 static int get_nicklist_entry(int nick) {
60 char *valid_chars = VALID_NICK_CHARS_FIRST;
61 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
62 if(valid_chars[i] == nick)
68 struct UserNode* getUserByNick(const char *nick) { //case sensitive
69 int userListIndex = get_nicklist_entry(*nick);
70 if(userListIndex == -1 || userList[userListIndex] == NULL)
72 SYNCHRONIZE(cache_sync);
73 struct UserNode *user;
74 for(user = userList[userListIndex]; user; user = user->next) {
75 if(!stricmp(nick, user->nick)) {
76 DESYNCHRONIZE(cache_sync);
80 DESYNCHRONIZE(cache_sync);
84 struct UserNode* getUserByMask(const char *mask) { //case sensitive
85 SYNCHRONIZE(cache_sync);
86 char cmask[strlen(mask)+1];
89 struct UserNode *user = NULL;
90 for(i = 0; i < strlen(mask); i++) {
93 user = getUserByNick(&cmask[0]);
94 DESYNCHRONIZE(cache_sync);
96 } else if(cmask[i] == '.') {
98 DESYNCHRONIZE(cache_sync);
102 DESYNCHRONIZE(cache_sync);
106 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
108 return getUserByNick(nick);
110 SYNCHRONIZE(cache_sync);
112 struct UserNode *user;
114 //search in the lower case "section"
115 userListIndex = get_nicklist_entry(tolower(*nick));
116 if(userListIndex != -1 && userList[userListIndex] != NULL) {
117 for(user = userList[userListIndex]; user; user = user->next) {
118 if(!stricmp(nick, user->nick)) {
119 DESYNCHRONIZE(cache_sync);
124 //search in the upper case "section"
125 userListIndex = get_nicklist_entry(toupper(*nick));
126 if(userListIndex != -1 && userList[userListIndex] != NULL) {
127 for(user = userList[userListIndex]; user; user = user->next) {
128 if(!stricmp(nick, user->nick)) {
129 DESYNCHRONIZE(cache_sync);
134 DESYNCHRONIZE(cache_sync);
138 int countUsersWithHost(char *host) {
139 SYNCHRONIZE(cache_sync);
141 struct UserNode *user;
142 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
143 for(user = userList[i]; user; user = user->next) {
144 if(!strcmp(user->host, host)) {
149 DESYNCHRONIZE(cache_sync);
153 char *getAuthFakehost(char *auth) {
154 SYNCHRONIZE(cache_sync);
156 struct UserNode *user;
157 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
158 for(user = userList[i]; user; user = user->next) {
159 if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
160 DESYNCHRONIZE(cache_sync);
165 DESYNCHRONIZE(cache_sync);
169 struct UserNode* getAllUsers(struct UserNode *last) {
170 SYNCHRONIZE(cache_sync);
171 if(last == NULL || last->next == NULL) {
176 cindex = get_nicklist_entry(last->nick[0]) + 1;
177 while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
179 DESYNCHRONIZE(cache_sync);
180 if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
181 return userList[cindex];
183 DESYNCHRONIZE(cache_sync);
188 struct UserNode* getUsersWithAuth(const char *auth, struct UserNode *last) {
189 SYNCHRONIZE(cache_sync);
190 int cindex = (last ? get_nicklist_entry(last->nick[0]) : 0);
191 struct UserNode *cuser = last;
192 while(cindex <= VALID_NICK_CHARS_FIRST_LEN) {
193 for(cuser = (cuser ? cuser->next : userList[cindex]); cuser; cuser = cuser->next) {
194 if((cuser->flags & USERFLAG_ISAUTHED) && !strcmp(cuser->auth, auth)) {
195 DESYNCHRONIZE(cache_sync);
202 DESYNCHRONIZE(cache_sync);
207 SYNCHRONIZE(cache_sync);
209 struct UserNode *user;
210 for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
211 for(user = userList[i]; user; user = user->next) {
215 DESYNCHRONIZE(cache_sync);
219 struct UserNode* addUser(const char *nick) {
220 int userListIndex = get_nicklist_entry(*nick);
221 if(userListIndex == -1 || !is_valid_nick(nick))
223 struct UserNode *user = malloc(sizeof(*user));
226 perror("malloc() failed");
229 strcpy(user->nick, nick);
230 user->created = time(0);
234 user->realname[0] = 0;
236 user->channel = NULL;
238 SYNCHRONIZE(cache_sync);
239 user->next = userList[userListIndex];
240 userList[userListIndex] = user;
241 DESYNCHRONIZE(cache_sync);
245 struct UserNode* addUserMask(const char *mask) {
246 char cmask[strlen(mask)+1];
249 struct UserNode *user = NULL;
250 for(i = 0; i < strlen(mask)+1; i++) {
251 if(cmask[i] == '!') {
253 user = addUser(cmask);
254 if(user == NULL) return NULL;
256 } else if(cmask[i] == '.' && !user) {
259 } else if(cmask[i] == '@') {
260 if(user == NULL) return NULL;
262 strcpy(user->ident, &cmask[ii]);
264 } else if(cmask[i] == '\0') {
265 if(user == NULL) return NULL;
266 strcpy(user->host, &cmask[ii]);
272 struct UserNode* createTempUser(const char *nick) {
273 int already_on_list = 0;
274 struct UserNode *user = NULL;
275 if(!is_valid_nick(nick)) {
278 for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
279 if(!stricmp(user->nick, nick)) {
285 user = malloc(sizeof(*user));
287 perror("malloc() failed");
293 user->realname[0] = 0;
295 user->channel = NULL;
298 user->flags &= ~USERFLAG_FREETMPUSER;
299 user->created = time(0);
300 if(user->created - user->last_who > REWHO_TIMEOUT)
301 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
302 strcpy(user->nick, nick);
303 if(!already_on_list) {
304 SYNCHRONIZE(cache_sync);
305 user->next = userList[TEMPUSER_LIST_INDEX];
306 userList[TEMPUSER_LIST_INDEX] = user;
307 DESYNCHRONIZE(cache_sync);
312 struct UserNode* createTempUserMask(const char *mask) {
313 //note: it could also be a server we have to create a temponary user for...
314 char cmask[strlen(mask)+1];
317 int already_on_list = 0;
318 struct UserNode *user = NULL;
319 for(i = 0; i < strlen(mask)+1; i++) {
320 if(cmask[i] == '!') {
322 if(!is_valid_nick(cmask)) {
325 for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
326 if(!stricmp(user->nick, cmask)) {
332 user = malloc(sizeof(*user));
334 perror("malloc() failed");
340 user->realname[0] = 0;
342 user->channel = NULL;
345 user->flags &= ~USERFLAG_FREETMPUSER;
346 user->created = time(0);
347 if(user->created - user->last_who > REWHO_TIMEOUT)
348 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
349 strcpy(user->nick, cmask);
351 } else if(cmask[i] == '.' && !user) {
353 user = malloc(sizeof(*user));
356 perror("malloc() failed");
359 strcpy(user->host, cmask);
360 strncpy(user->nick, cmask, NICKLEN);
361 user->nick[NICKLEN] = 0;
362 user->created = time(0);
366 user->realname[0] = 0;
367 user->flags = USERFLAG_ISSERVER;
368 user->channel = NULL;
371 } else if(cmask[i] == '@') {
372 if(user == NULL) return NULL;
374 strcpy(user->ident, &cmask[ii]);
376 } else if(cmask[i] == '\0') {
379 user = malloc(sizeof(*user));
382 perror("malloc() failed");
385 strcpy(user->nick, cmask);
386 user->created = time(0);
390 user->realname[0] = 0;
392 user->channel = NULL;
396 strcpy(user->host, &cmask[ii]);
399 if(!already_on_list) {
400 SYNCHRONIZE(cache_sync);
401 user->next = userList[TEMPUSER_LIST_INDEX];
402 userList[TEMPUSER_LIST_INDEX] = user;
403 DESYNCHRONIZE(cache_sync);
408 int renameUser(struct UserNode* user, const char *new_nick) {
409 if(!is_valid_nick(new_nick))
411 if(user->nick[0] == *new_nick) {
412 strcpy(user->nick, new_nick);
415 //delUser(user, 0); //EPIC FAIL! This deletes the user from the channel Userlist -.-
416 //manually remove the user from the old userList
417 SYNCHRONIZE(cache_sync);
418 int userListIndex = get_nicklist_entry(user->nick[0]);
419 if(userListIndex != -1) {
420 struct UserNode *cuser, *last_user = NULL;
421 for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
424 last_user->next = user->next;
426 userList[userListIndex] = user->next;
432 userListIndex = get_nicklist_entry(*new_nick);
433 strcpy(user->nick, new_nick);
434 user->next = userList[userListIndex];
435 userList[userListIndex] = user;
436 DESYNCHRONIZE(cache_sync);
440 void delUser(struct UserNode* user, int freeUser) {
441 int userListIndex = ((user->flags & USERFLAG_ISTMPUSER) ? TEMPUSER_LIST_INDEX : get_nicklist_entry(user->nick[0]));
442 if(userListIndex == -1) return;
443 SYNCHRONIZE(cache_sync);
444 event_freeuser(user);
445 struct UserNode *cuser, *last_user = NULL;
446 for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
449 last_user->next = user->next;
451 userList[userListIndex] = user->next;
456 if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
457 user->flags |= USERFLAG_FREE_AFTER_WHO;
461 struct ChanUser *chanUser, *next;
462 for(chanUser = user->channel; chanUser; chanUser = next) {
463 next = chanUser->next_chan;
464 removeChanUserFromLists(chanUser, 1, 0, freeUser);
469 freeIPNode(user->ip);
473 DESYNCHRONIZE(cache_sync);
476 void clearTempUsers() {
477 SYNCHRONIZE(cache_sync);
478 int userListIndex = TEMPUSER_LIST_INDEX;
479 struct UserNode *cuser, *next;
480 time_t now = time(0);
481 for(cuser = userList[userListIndex]; cuser; cuser = next) {
483 if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
487 DESYNCHRONIZE(cache_sync);