Merge branch 'development'
[NeonServV5.git] / src / UserNode.c
1 /* UserNode.c - NeonServ v5.6
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 #include "log.h"
24
25 static struct UserNode **userList;
26
27 unsigned int valid_user_modes[] = {
28     1,  'o',
29     2,  'O',
30     3,  'i',
31     4,  'w',
32     5,  's',
33     6,  'd',
34     7,  'k',
35     8,  'g',
36     9,  'n',
37     10, 'I',
38     11, 'X',
39     12, 'S',
40     13, 'H',
41     14, 'c',
42     15, 'W',
43     16, 't',
44     17, 'D',
45     18, 'x',
46 //  ^ maximum is 32!!!
47     0x00, 0x00
48 };
49
50 void init_UserNode() {
51     unsigned int *mode, flag = 1;
52     userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
53     for (mode = valid_user_modes; mode[1]; mode += 2) {
54         mode[0] = flag;
55         flag = flag << 1;
56     }
57 }
58
59 void free_UserNode() {
60     //kamikaze free all users
61     //chanusers will be destroyed in free_ChanNode()
62     int i;
63     struct UserNode *user, *next;
64     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
65         for(user = userList[i]; user; user = next) {
66             next = user->next;
67             free(user);
68         }
69     }
70     free(userList);
71 }
72
73 int is_valid_nick(const char *nick) {
74     unsigned int i;
75     //first char must be one of: a-zA-Z{|}~[\]^_`
76     if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
77         return 0;
78     //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
79     for (i = 0; nick[i]; ++i)
80         if (!strchr(VALID_NICK_CHARS, nick[i]))
81             return 0;
82     if (strlen(nick) > NICKLEN)
83         return 0;
84     return 1;
85 }
86
87 static int get_nicklist_entry(int nick) {
88     int i;
89     char *valid_chars = VALID_NICK_CHARS_FIRST;
90     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
91         if(valid_chars[i] == nick)
92             return i;
93     }
94     return -1; //ERROR!
95 }
96
97 static unsigned int* getUserModeOptions(char mode) {
98     unsigned int *cmode;
99     for (cmode = valid_user_modes; cmode[1]; cmode += 2) {
100         if(cmode[1] == mode)
101             return cmode;
102     }
103     return NULL;
104 }
105
106 int isUserModeSet(struct UserNode *user, char modeChar) {
107     unsigned int *modeOpt = getUserModeOptions(modeChar);
108     return (user->usermode & modeOpt[0]);
109 }
110
111 void parseUserModes(struct UserNode* user, char *modeStr) {
112     int i, add = 1;
113     unsigned int *modeOpt;
114     for(i = 0; i < strlen(modeStr); i++) {
115         if(modeStr[i] == '+') {
116             add = 1;
117             continue;
118         }
119         if(modeStr[i] == '-') {
120             add = 0;
121             continue;
122         }
123         modeOpt = getUserModeOptions(modeStr[i]);
124         if(!modeOpt) continue; // unknown mode?
125         if(add) {
126             user->usermode |= modeOpt[0];
127         } else {
128             user->usermode &= ~modeOpt[0];
129         }
130     }
131 }
132
133
134 struct UserNode* getUserByNick(const char *nick) { //case sensitive
135     int userListIndex = get_nicklist_entry(*nick);
136     if(userListIndex == -1 || userList[userListIndex] == NULL)
137         return NULL;
138     SYNCHRONIZE(cache_sync);
139     struct UserNode *user;
140     for(user = userList[userListIndex]; user; user = user->next) {
141         if(!stricmp(nick, user->nick)) {
142             DESYNCHRONIZE(cache_sync);
143             return user;
144         }
145     }
146     DESYNCHRONIZE(cache_sync);
147     return NULL;
148 }
149
150 struct UserNode* getUserByMask(const char *mask) { //case sensitive
151     SYNCHRONIZE(cache_sync);
152     char cmask[strlen(mask)+1];
153     strcpy(cmask, mask);
154     int i;
155     struct UserNode *user = NULL;
156     for(i = 0; i < strlen(mask); i++) {
157         if(cmask[i] == '!') {
158             cmask[i] = 0;
159             user = getUserByNick(&cmask[0]);
160             DESYNCHRONIZE(cache_sync);
161             return user;
162         } else if(cmask[i] == '.') {
163             //it's a server
164             DESYNCHRONIZE(cache_sync);
165             return NULL;
166         }
167     }
168     DESYNCHRONIZE(cache_sync);
169     return NULL;
170 }
171
172 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
173     if(!isalpha(*nick)) 
174         return getUserByNick(nick);
175
176     SYNCHRONIZE(cache_sync);
177     int userListIndex;
178     struct UserNode *user;
179
180     //search in the lower case "section"
181     userListIndex = get_nicklist_entry(tolower(*nick));
182     if(userListIndex != -1 && userList[userListIndex] != NULL) {
183         for(user = userList[userListIndex]; user; user = user->next) {
184             if(!stricmp(nick, user->nick)) {
185                 DESYNCHRONIZE(cache_sync);
186                 return user;
187             }
188         }
189     }
190     //search in the upper case "section"
191     userListIndex = get_nicklist_entry(toupper(*nick));
192     if(userListIndex != -1 && userList[userListIndex] != NULL) {
193         for(user = userList[userListIndex]; user; user = user->next) {
194             if(!stricmp(nick, user->nick)) {
195                 DESYNCHRONIZE(cache_sync);
196                 return user;
197             }
198         }
199     }
200     DESYNCHRONIZE(cache_sync);
201     return NULL;
202 }
203
204 int countUsersWithHost(char *host) {
205     SYNCHRONIZE(cache_sync);
206     int i, count = 0;
207     struct UserNode *user;
208     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
209         for(user = userList[i]; user; user = user->next) {
210             if(!strcmp(user->host, host)) {
211                 count++;
212             }
213         }
214     }
215     DESYNCHRONIZE(cache_sync);
216     return count;
217 }
218
219 char *getAuthFakehost(char *auth) {
220     SYNCHRONIZE(cache_sync);
221     int i;
222     struct UserNode *user;
223     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
224         for(user = userList[i]; user; user = user->next) {
225             if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
226                 DESYNCHRONIZE(cache_sync);
227                 return user->host;
228             }
229         }
230     }
231     DESYNCHRONIZE(cache_sync);
232     return NULL;
233 }
234
235 struct UserNode* getAllUsers(struct UserNode *last) {
236     SYNCHRONIZE(cache_sync);
237     if(last == NULL || last->next == NULL) {
238         int cindex;
239         if(last == NULL)
240             cindex = 0;
241         else
242             cindex = get_nicklist_entry(last->nick[0]) + 1;
243         while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
244             cindex++;
245         DESYNCHRONIZE(cache_sync);
246         if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
247         return userList[cindex];
248     } else {
249         DESYNCHRONIZE(cache_sync);
250         return last->next;
251     }
252 }
253
254 struct UserNode* getUsersWithAuth(const char *auth, struct UserNode *last) {
255     SYNCHRONIZE(cache_sync);
256     int cindex = (last ? get_nicklist_entry(last->nick[0]) : 0);
257     struct UserNode *cuser = last;
258     while(cindex <= VALID_NICK_CHARS_FIRST_LEN) {
259         for(cuser = (cuser ? cuser->next : userList[cindex]); cuser; cuser = cuser->next) {
260             if((cuser->flags & USERFLAG_ISAUTHED) && !strcmp(cuser->auth, auth)) {
261                 DESYNCHRONIZE(cache_sync);
262                 return cuser;
263             }
264         }
265         cindex++;
266         cuser = NULL;
267     }
268     DESYNCHRONIZE(cache_sync);
269     return NULL;
270 }
271
272 int getUserCount() {
273     SYNCHRONIZE(cache_sync);
274     int i, count = 0;
275     struct UserNode *user;
276     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
277         for(user = userList[i]; user; user = user->next) {
278             count++;
279         }
280     }
281     DESYNCHRONIZE(cache_sync);
282     return count;
283 }
284
285 struct UserNode* addUser(const char *nick) {
286     int userListIndex = get_nicklist_entry(*nick);
287     if(userListIndex == -1 || !is_valid_nick(nick))
288         return NULL;
289     struct UserNode *user = malloc(sizeof(*user));
290     if (!user)
291     {
292         printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
293         return NULL;
294     }
295     strcpy(user->nick, nick);
296     user->created = time(0);
297     user->ident[0] = 0;
298     user->host[0] = 0;
299     user->ip = NULL;
300     user->realname[0] = 0;
301     user->flags = 0;
302     user->channel = NULL;
303     user->last_who = 0;
304     user->usermode = 0;
305     SYNCHRONIZE(cache_sync);
306     user->next = userList[userListIndex];
307     userList[userListIndex] = user;
308     DESYNCHRONIZE(cache_sync);
309     return user;
310 }
311
312 struct UserNode* addUserMask(const char *mask) {
313     char cmask[strlen(mask)+1];
314     strcpy(cmask, mask);
315     int i, ii = 0;
316     struct UserNode *user = NULL;
317     for(i = 0; i < strlen(mask)+1; i++) {
318         if(cmask[i] == '!') {
319             cmask[i] = 0;
320             user = addUser(cmask);
321             if(user == NULL) return NULL;
322             ii = i+1;
323         } else if(cmask[i] == '.' && !user) {
324             //it's a server
325             return NULL;
326         } else if(cmask[i] == '@') {
327             if(user == NULL) return NULL;
328             cmask[i] = 0;
329             strcpy(user->ident, &cmask[ii]);
330             ii = i+1;
331         } else if(cmask[i] == '\0') {
332             if(user == NULL) return NULL;
333             strcpy(user->host, &cmask[ii]);
334         }
335     }
336     return user;
337 }
338
339 struct UserNode* createTempUser(const char *nick) {
340     int already_on_list = 0;
341     struct UserNode *user = NULL;
342     if(!is_valid_nick(nick)) {
343         return NULL;
344     }
345     for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
346         if(!stricmp(user->nick, nick)) {
347             already_on_list = 1;
348             break;
349         }
350     }
351     if(!user) {
352         user = malloc(sizeof(*user));
353         if (!user) {
354             printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
355             return NULL;
356         }
357         user->ident[0] = 0;
358         user->host[0] = 0;
359         user->ip = NULL;
360         user->realname[0] = 0;
361         user->flags = 0;
362         user->channel = NULL;
363         user->usermode = 0;
364         user->last_who = 0;
365     } else
366         user->flags &= ~USERFLAG_FREETMPUSER;
367     user->created = time(0);
368     if(user->created - user->last_who > REWHO_TIMEOUT)
369         user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
370     strcpy(user->nick, nick);
371     if(!already_on_list) {
372         SYNCHRONIZE(cache_sync);
373         user->next = userList[TEMPUSER_LIST_INDEX];
374         userList[TEMPUSER_LIST_INDEX] = user;
375         DESYNCHRONIZE(cache_sync);
376     }
377     return user;
378 }
379
380 struct UserNode* createTempUserMask(const char *mask) {
381     //note: it could also be a server we have to create a temponary user for...
382     char cmask[strlen(mask)+1];
383     strcpy(cmask, mask);
384     int i, ii = 0;
385     int already_on_list = 0;
386     struct UserNode *user = NULL;
387     for(i = 0; i < strlen(mask)+1; i++) {
388         if(cmask[i] == '!') {
389             cmask[i] = 0;
390             if(!is_valid_nick(cmask)) {
391                 return NULL;
392             }
393             for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
394                 if(!stricmp(user->nick, cmask)) {
395                     already_on_list = 1;
396                     break;
397                 }
398             }
399             if(!user) {
400                 user = malloc(sizeof(*user));
401                 if (!user) {
402                     printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
403                     return NULL;
404                 }
405                 user->ident[0] = 0;
406                 user->host[0] = 0;
407                 user->ip = NULL;
408                 user->realname[0] = 0;
409                 user->flags = 0;
410                 user->channel = NULL;
411                 user->usermode = 0;
412                 user->last_who = 0;
413             } else
414                 user->flags &= ~USERFLAG_FREETMPUSER;
415             user->created = time(0);
416             if(user->created - user->last_who > REWHO_TIMEOUT)
417                 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
418             strcpy(user->nick, cmask);
419             ii = i+1;
420         } else if(cmask[i] == '.' && !user) {
421             //it's a server
422             user = malloc(sizeof(*user));
423             if (!user)
424             {
425                 printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
426                 return NULL;
427             }
428             strcpy(user->host, cmask);
429             strncpy(user->nick, cmask, NICKLEN);
430             user->nick[NICKLEN] = 0;
431             user->created = time(0);
432             user->ident[0] = 0;
433             user->host[0] = 0;
434             user->ip = NULL;
435             user->realname[0] = 0;
436             user->flags = USERFLAG_ISSERVER;
437             user->channel = NULL;
438             user->usermode = 0;
439             user->last_who = 0;
440             break;
441         } else if(cmask[i] == '@') {
442             if(user == NULL) return NULL;
443             cmask[i] = 0;
444             strcpy(user->ident, &cmask[ii]);
445             ii = i+1;
446         } else if(cmask[i] == '\0') {
447             if(user == NULL) {
448                 //nick only
449                 user = malloc(sizeof(*user));
450                 if (!user)
451                 {
452                     printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
453                     return NULL;
454                 }
455                 strcpy(user->nick, cmask);
456                 user->created = time(0);
457                 user->ident[0] = 0;
458                 user->host[0] = 0;
459                 user->ip = NULL;
460                 user->realname[0] = 0;
461                 user->flags = 0;
462                 user->channel = NULL;
463                 user->usermode = 0;
464                 user->last_who = 0;
465                 break;
466             }
467             strcpy(user->host, &cmask[ii]);
468         }
469     }
470     if(!already_on_list) {
471         SYNCHRONIZE(cache_sync);
472         user->next = userList[TEMPUSER_LIST_INDEX];
473         userList[TEMPUSER_LIST_INDEX] = user;
474         DESYNCHRONIZE(cache_sync);
475     }
476     return user;
477 }
478
479 int renameUser(struct UserNode* user, const char *new_nick) {
480     if(!is_valid_nick(new_nick))
481         return 0;
482     if(user->nick[0] == *new_nick) {
483         strcpy(user->nick, new_nick);
484         return 1;
485     }
486     //delUser(user, 0); //EPIC FAIL! This deletes the user from the channel Userlist -.-
487     //manually remove the user from the old userList
488     SYNCHRONIZE(cache_sync);
489     int userListIndex = get_nicklist_entry(user->nick[0]);
490     if(userListIndex != -1) {
491         struct UserNode *cuser, *last_user = NULL;
492         for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
493             if(cuser == user) {
494                 if(last_user)
495                     last_user->next = user->next;
496                 else
497                     userList[userListIndex] = user->next;
498                 break;
499             } else
500                 last_user = cuser;
501         }
502     }
503     userListIndex = get_nicklist_entry(*new_nick);
504     strcpy(user->nick, new_nick);
505     user->next = userList[userListIndex];
506     userList[userListIndex] = user;
507     DESYNCHRONIZE(cache_sync);
508     return 1;
509 }
510
511 void delUser(struct UserNode* user, int freeUser) {
512     int userListIndex = ((user->flags & USERFLAG_ISTMPUSER) ? TEMPUSER_LIST_INDEX : get_nicklist_entry(user->nick[0]));
513     if(userListIndex == -1) return;
514     SYNCHRONIZE(cache_sync);
515     event_freeuser(user);
516     struct UserNode *cuser, *last_user = NULL;
517     for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
518         if(cuser == user) {
519             if(last_user)
520                 last_user->next = user->next;
521             else
522                 userList[userListIndex] = user->next;
523             break;
524         } else
525             last_user = cuser;
526     }
527     if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
528         user->flags |= USERFLAG_FREE_AFTER_WHO;
529         freeUser = 0;
530     }
531     if(user->channel) {
532         struct ChanUser *chanUser, *next;
533         for(chanUser = user->channel; chanUser; chanUser = next) {
534             next = chanUser->next_chan;
535             removeChanUserFromLists(chanUser, 1, 0, freeUser);
536         }
537     }
538     if(freeUser) {
539         if(user->ip)
540             freeIPNode(user->ip);
541         free(user);
542     } else
543         user->next = NULL;
544     DESYNCHRONIZE(cache_sync);
545 }
546
547 void clearTempUsers() {
548     SYNCHRONIZE(cache_sync);
549     int userListIndex = TEMPUSER_LIST_INDEX;
550     struct UserNode *cuser, *next;
551     time_t now = time(0);
552     for(cuser = userList[userListIndex]; cuser; cuser = next) {
553         next = cuser->next;
554         if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
555             delUser(cuser, 1);
556         }
557     }
558     DESYNCHRONIZE(cache_sync);
559 }