*** VERSION 5.4.0 ***
[NeonServV5.git] / src / UserNode.c
1 /* UserNode.c - NeonServ v5.4
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
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.
8  * 
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.
13  * 
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/>. 
16  */
17 #include "UserNode.h"
18 #include "ChanNode.h"
19 #include "ChanUser.h"
20 #include "tools.h"
21 #include "IRCEvents.h"
22 #include "IPNode.h"
23
24 static struct UserNode **userList;
25
26 void init_UserNode() {
27     userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
28 }
29
30 void free_UserNode() {
31     //kamikaze free all users
32     //chanusers will be destroyed in free_ChanNode()
33     int i;
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) {
37             next = user->next;
38             free(user);
39         }
40     }
41     free(userList);
42 }
43
44 int is_valid_nick(const char *nick) {
45     unsigned int i;
46     //first char must be one of: a-zA-Z{|}~[\]^_`
47     if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
48         return 0;
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]))
52             return 0;
53     if (strlen(nick) > NICKLEN)
54         return 0;
55     return 1;
56 }
57
58 static int get_nicklist_entry(int nick) {
59     int i;
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)
63             return i;
64     }
65     return -1; //ERROR!
66 }
67
68 struct UserNode* getUserByNick(const char *nick) { //case sensitive
69     int userListIndex = get_nicklist_entry(*nick);
70     if(userListIndex == -1 || userList[userListIndex] == NULL)
71         return 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);
77             return user;
78         }
79     }
80     DESYNCHRONIZE(cache_sync);
81     return NULL;
82 }
83
84 struct UserNode* getUserByMask(const char *mask) { //case sensitive
85     SYNCHRONIZE(cache_sync);
86     char cmask[strlen(mask)+1];
87     strcpy(cmask, mask);
88     int i;
89     struct UserNode *user = NULL;
90     for(i = 0; i < strlen(mask); i++) {
91         if(cmask[i] == '!') {
92             cmask[i] = 0;
93             user = getUserByNick(&cmask[0]);
94             DESYNCHRONIZE(cache_sync);
95             return user;
96         } else if(cmask[i] == '.') {
97             //it's a server
98             DESYNCHRONIZE(cache_sync);
99             return NULL;
100         }
101     }
102     DESYNCHRONIZE(cache_sync);
103     return NULL;
104 }
105
106 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
107     if(!isalpha(*nick)) 
108         return getUserByNick(nick);
109
110     SYNCHRONIZE(cache_sync);
111     int userListIndex;
112     struct UserNode *user;
113
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);
120                 return user;
121             }
122         }
123     }
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);
130                 return user;
131             }
132         }
133     }
134     DESYNCHRONIZE(cache_sync);
135     return NULL;
136 }
137
138 int countUsersWithHost(char *host) {
139     SYNCHRONIZE(cache_sync);
140     int i, count = 0;
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)) {
145                 count++;
146             }
147         }
148     }
149     DESYNCHRONIZE(cache_sync);
150     return count;
151 }
152
153 char *getAuthFakehost(char *auth) {
154     SYNCHRONIZE(cache_sync);
155     int i;
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);
161                 return user->host;
162             }
163         }
164     }
165     DESYNCHRONIZE(cache_sync);
166     return NULL;
167 }
168
169 struct UserNode* getAllUsers(struct UserNode *last) {
170     SYNCHRONIZE(cache_sync);
171     if(last == NULL || last->next == NULL) {
172         int cindex;
173         if(last == NULL)
174             cindex = 0;
175         else
176             cindex = get_nicklist_entry(last->nick[0]) + 1;
177         while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
178             cindex++;
179         DESYNCHRONIZE(cache_sync);
180         if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
181         return userList[cindex];
182     } else {
183         DESYNCHRONIZE(cache_sync);
184         return last->next;
185     }
186 }
187
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);
196                 return cuser;
197             }
198         }
199         cindex++;
200         cuser = NULL;
201     }
202     DESYNCHRONIZE(cache_sync);
203     return NULL;
204 }
205
206 int getUserCount() {
207     SYNCHRONIZE(cache_sync);
208     int i, count = 0;
209     struct UserNode *user;
210     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
211         for(user = userList[i]; user; user = user->next) {
212             count++;
213         }
214     }
215     DESYNCHRONIZE(cache_sync);
216     return count;
217 }
218
219 struct UserNode* addUser(const char *nick) {
220     int userListIndex = get_nicklist_entry(*nick);
221     if(userListIndex == -1 || !is_valid_nick(nick))
222         return NULL;
223     struct UserNode *user = malloc(sizeof(*user));
224     if (!user)
225     {
226         perror("malloc() failed");
227         return NULL;
228     }
229     strcpy(user->nick, nick);
230     user->created = time(0);
231     user->ident[0] = 0;
232     user->host[0] = 0;
233     user->ip = NULL;
234     user->realname[0] = 0;
235     user->flags = 0;
236     user->channel = NULL;
237     user->last_who = 0;
238     SYNCHRONIZE(cache_sync);
239     user->next = userList[userListIndex];
240     userList[userListIndex] = user;
241     DESYNCHRONIZE(cache_sync);
242     return user;
243 }
244
245 struct UserNode* addUserMask(const char *mask) {
246     char cmask[strlen(mask)+1];
247     strcpy(cmask, mask);
248     int i, ii = 0;
249     struct UserNode *user = NULL;
250     for(i = 0; i < strlen(mask)+1; i++) {
251         if(cmask[i] == '!') {
252             cmask[i] = 0;
253             user = addUser(cmask);
254             if(user == NULL) return NULL;
255             ii = i+1;
256         } else if(cmask[i] == '.' && !user) {
257             //it's a server
258             return NULL;
259         } else if(cmask[i] == '@') {
260             if(user == NULL) return NULL;
261             cmask[i] = 0;
262             strcpy(user->ident, &cmask[ii]);
263             ii = i+1;
264         } else if(cmask[i] == '\0') {
265             if(user == NULL) return NULL;
266             strcpy(user->host, &cmask[ii]);
267         }
268     }
269     return user;
270 }
271
272 struct UserNode* createTempUser(const char *nick) {
273     int already_on_list = 0;
274     struct UserNode *user = NULL;
275     if(!is_valid_nick(nick)) {
276         return NULL;
277     }
278     for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
279         if(!stricmp(user->nick, nick)) {
280             already_on_list = 1;
281             break;
282         }
283     }
284     if(!user) {
285         user = malloc(sizeof(*user));
286         if (!user) {
287             perror("malloc() failed");
288             return NULL;
289         }
290         user->ident[0] = 0;
291         user->host[0] = 0;
292         user->ip = NULL;
293         user->realname[0] = 0;
294         user->flags = 0;
295         user->channel = NULL;
296         user->last_who = 0;
297     } else
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);
308     }
309     return user;
310 }
311
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];
315     strcpy(cmask, mask);
316     int i, ii = 0;
317     int already_on_list = 0;
318     struct UserNode *user = NULL;
319     for(i = 0; i < strlen(mask)+1; i++) {
320         if(cmask[i] == '!') {
321             cmask[i] = 0;
322             if(!is_valid_nick(cmask)) {
323                 return NULL;
324             }
325             for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
326                 if(!stricmp(user->nick, cmask)) {
327                     already_on_list = 1;
328                     break;
329                 }
330             }
331             if(!user) {
332                 user = malloc(sizeof(*user));
333                 if (!user) {
334                     perror("malloc() failed");
335                     return NULL;
336                 }
337                 user->ident[0] = 0;
338                 user->host[0] = 0;
339                 user->ip = NULL;
340                 user->realname[0] = 0;
341                 user->flags = 0;
342                 user->channel = NULL;
343                 user->last_who = 0;
344             } else
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);
350             ii = i+1;
351         } else if(cmask[i] == '.' && !user) {
352             //it's a server
353             user = malloc(sizeof(*user));
354             if (!user)
355             {
356                 perror("malloc() failed");
357                 return NULL;
358             }
359             strcpy(user->host, cmask);
360             strncpy(user->nick, cmask, NICKLEN);
361             user->nick[NICKLEN] = 0;
362             user->created = time(0);
363             user->ident[0] = 0;
364             user->host[0] = 0;
365             user->ip = NULL;
366             user->realname[0] = 0;
367             user->flags = USERFLAG_ISSERVER;
368             user->channel = NULL;
369             user->last_who = 0;
370             break;
371         } else if(cmask[i] == '@') {
372             if(user == NULL) return NULL;
373             cmask[i] = 0;
374             strcpy(user->ident, &cmask[ii]);
375             ii = i+1;
376         } else if(cmask[i] == '\0') {
377             if(user == NULL) {
378                 //nick only
379                 user = malloc(sizeof(*user));
380                 if (!user)
381                 {
382                     perror("malloc() failed");
383                     return NULL;
384                 }
385                 strcpy(user->nick, cmask);
386                 user->created = time(0);
387                 user->ident[0] = 0;
388                 user->host[0] = 0;
389                 user->ip = NULL;
390                 user->realname[0] = 0;
391                 user->flags = 0;
392                 user->channel = NULL;
393                 user->last_who = 0;
394                 break;
395             }
396             strcpy(user->host, &cmask[ii]);
397         }
398     }
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);
404     }
405     return user;
406 }
407
408 int renameUser(struct UserNode* user, const char *new_nick) {
409     if(!is_valid_nick(new_nick))
410         return 0;
411     if(user->nick[0] == *new_nick) {
412         strcpy(user->nick, new_nick);
413         return 1;
414     }
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) {
422             if(cuser == user) {
423                 if(last_user)
424                     last_user->next = user->next;
425                 else
426                     userList[userListIndex] = user->next;
427                 break;
428             } else
429                 last_user = cuser;
430         }
431     }
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);
437     return 1;
438 }
439
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) {
447         if(cuser == user) {
448             if(last_user)
449                 last_user->next = user->next;
450             else
451                 userList[userListIndex] = user->next;
452             break;
453         } else
454             last_user = cuser;
455     }
456     if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
457         user->flags |= USERFLAG_FREE_AFTER_WHO;
458         freeUser = 0;
459     }
460     if(user->channel) {
461         struct ChanUser *chanUser, *next;
462         for(chanUser = user->channel; chanUser; chanUser = next) {
463             next = chanUser->next_chan;
464             removeChanUserFromLists(chanUser, 1, 0, freeUser);
465         }
466     }
467     if(freeUser) {
468         if(user->ip)
469             freeIPNode(user->ip);
470         free(user);
471     } else
472         user->next = NULL;
473     DESYNCHRONIZE(cache_sync);
474 }
475
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) {
482         next = cuser->next;
483         if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
484             delUser(cuser, 1);
485         }
486     }
487     DESYNCHRONIZE(cache_sync);
488 }