fixed path of mysql/errmsg.h (OSX compilation fix)
[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
24 static struct UserNode **userList;
25
26 unsigned int valid_user_modes[] = {
27     1,  'o',
28     2,  'O',
29     3,  'i',
30     4,  'w',
31     5,  's',
32     6,  'd',
33     7,  'k',
34     8,  'g',
35     9,  'n',
36     10, 'I',
37     11, 'X',
38     12, 'S',
39     13, 'H',
40     14, 'c',
41     15, 'W',
42     16, 't',
43     17, 'D',
44     18, 'x',
45 //  ^ maximum is 32!!!
46     0x00, 0x00
47 };
48
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) {
53         mode[0] = flag;
54         flag = flag << 1;
55     }
56 }
57
58 void free_UserNode() {
59     //kamikaze free all users
60     //chanusers will be destroyed in free_ChanNode()
61     int i;
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) {
65             next = user->next;
66             free(user);
67         }
68     }
69     free(userList);
70 }
71
72 int is_valid_nick(const char *nick) {
73     unsigned int i;
74     //first char must be one of: a-zA-Z{|}~[\]^_`
75     if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
76         return 0;
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]))
80             return 0;
81     if (strlen(nick) > NICKLEN)
82         return 0;
83     return 1;
84 }
85
86 static int get_nicklist_entry(int nick) {
87     int i;
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)
91             return i;
92     }
93     return -1; //ERROR!
94 }
95
96 static unsigned int* getUserModeOptions(char mode) {
97     unsigned int *cmode;
98     for (cmode = valid_user_modes; cmode[1]; cmode += 2) {
99         if(cmode[1] == mode)
100             return cmode;
101     }
102     return NULL;
103 }
104
105 int isUserModeSet(struct UserNode *user, char modeChar) {
106     unsigned int *modeOpt = getUserModeOptions(modeChar);
107     return (user->usermode & modeOpt[0]);
108 }
109
110 void parseUserModes(struct UserNode* user, char *modeStr) {
111     int i, add = 1;
112     unsigned int *modeOpt;
113     for(i = 0; i < strlen(modeStr); i++) {
114         if(modeStr[i] == '+') {
115             add = 1;
116             continue;
117         }
118         if(modeStr[i] == '-') {
119             add = 0;
120             continue;
121         }
122         modeOpt = getUserModeOptions(modeStr[i]);
123         if(!modeOpt) continue; // unknown mode?
124         if(add) {
125             user->usermode |= modeOpt[0];
126         } else {
127             user->usermode &= ~modeOpt[0];
128         }
129     }
130 }
131
132
133 struct UserNode* getUserByNick(const char *nick) { //case sensitive
134     int userListIndex = get_nicklist_entry(*nick);
135     if(userListIndex == -1 || userList[userListIndex] == NULL)
136         return 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);
142             return user;
143         }
144     }
145     DESYNCHRONIZE(cache_sync);
146     return NULL;
147 }
148
149 struct UserNode* getUserByMask(const char *mask) { //case sensitive
150     SYNCHRONIZE(cache_sync);
151     char cmask[strlen(mask)+1];
152     strcpy(cmask, mask);
153     int i;
154     struct UserNode *user = NULL;
155     for(i = 0; i < strlen(mask); i++) {
156         if(cmask[i] == '!') {
157             cmask[i] = 0;
158             user = getUserByNick(&cmask[0]);
159             DESYNCHRONIZE(cache_sync);
160             return user;
161         } else if(cmask[i] == '.') {
162             //it's a server
163             DESYNCHRONIZE(cache_sync);
164             return NULL;
165         }
166     }
167     DESYNCHRONIZE(cache_sync);
168     return NULL;
169 }
170
171 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
172     if(!isalpha(*nick)) 
173         return getUserByNick(nick);
174
175     SYNCHRONIZE(cache_sync);
176     int userListIndex;
177     struct UserNode *user;
178
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);
185                 return user;
186             }
187         }
188     }
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);
195                 return user;
196             }
197         }
198     }
199     DESYNCHRONIZE(cache_sync);
200     return NULL;
201 }
202
203 int countUsersWithHost(char *host) {
204     SYNCHRONIZE(cache_sync);
205     int i, count = 0;
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)) {
210                 count++;
211             }
212         }
213     }
214     DESYNCHRONIZE(cache_sync);
215     return count;
216 }
217
218 char *getAuthFakehost(char *auth) {
219     SYNCHRONIZE(cache_sync);
220     int i;
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);
226                 return user->host;
227             }
228         }
229     }
230     DESYNCHRONIZE(cache_sync);
231     return NULL;
232 }
233
234 struct UserNode* getAllUsers(struct UserNode *last) {
235     SYNCHRONIZE(cache_sync);
236     if(last == NULL || last->next == NULL) {
237         int cindex;
238         if(last == NULL)
239             cindex = 0;
240         else
241             cindex = get_nicklist_entry(last->nick[0]) + 1;
242         while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
243             cindex++;
244         DESYNCHRONIZE(cache_sync);
245         if(cindex >= VALID_NICK_CHARS_FIRST_LEN) return NULL;
246         return userList[cindex];
247     } else {
248         DESYNCHRONIZE(cache_sync);
249         return last->next;
250     }
251 }
252
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);
261                 return cuser;
262             }
263         }
264         cindex++;
265         cuser = NULL;
266     }
267     DESYNCHRONIZE(cache_sync);
268     return NULL;
269 }
270
271 int getUserCount() {
272     SYNCHRONIZE(cache_sync);
273     int i, count = 0;
274     struct UserNode *user;
275     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
276         for(user = userList[i]; user; user = user->next) {
277             count++;
278         }
279     }
280     DESYNCHRONIZE(cache_sync);
281     return count;
282 }
283
284 struct UserNode* addUser(const char *nick) {
285     int userListIndex = get_nicklist_entry(*nick);
286     if(userListIndex == -1 || !is_valid_nick(nick))
287         return NULL;
288     struct UserNode *user = malloc(sizeof(*user));
289     if (!user)
290     {
291         perror("malloc() failed");
292         return NULL;
293     }
294     strcpy(user->nick, nick);
295     user->created = time(0);
296     user->ident[0] = 0;
297     user->host[0] = 0;
298     user->ip = NULL;
299     user->realname[0] = 0;
300     user->flags = 0;
301     user->channel = NULL;
302     user->last_who = 0;
303     user->usermode = 0;
304     SYNCHRONIZE(cache_sync);
305     user->next = userList[userListIndex];
306     userList[userListIndex] = user;
307     DESYNCHRONIZE(cache_sync);
308     return user;
309 }
310
311 struct UserNode* addUserMask(const char *mask) {
312     char cmask[strlen(mask)+1];
313     strcpy(cmask, mask);
314     int i, ii = 0;
315     struct UserNode *user = NULL;
316     for(i = 0; i < strlen(mask)+1; i++) {
317         if(cmask[i] == '!') {
318             cmask[i] = 0;
319             user = addUser(cmask);
320             if(user == NULL) return NULL;
321             ii = i+1;
322         } else if(cmask[i] == '.' && !user) {
323             //it's a server
324             return NULL;
325         } else if(cmask[i] == '@') {
326             if(user == NULL) return NULL;
327             cmask[i] = 0;
328             strcpy(user->ident, &cmask[ii]);
329             ii = i+1;
330         } else if(cmask[i] == '\0') {
331             if(user == NULL) return NULL;
332             strcpy(user->host, &cmask[ii]);
333         }
334     }
335     return user;
336 }
337
338 struct UserNode* createTempUser(const char *nick) {
339     int already_on_list = 0;
340     struct UserNode *user = NULL;
341     if(!is_valid_nick(nick)) {
342         return NULL;
343     }
344     for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
345         if(!stricmp(user->nick, nick)) {
346             already_on_list = 1;
347             break;
348         }
349     }
350     if(!user) {
351         user = malloc(sizeof(*user));
352         if (!user) {
353             perror("malloc() failed");
354             return NULL;
355         }
356         user->ident[0] = 0;
357         user->host[0] = 0;
358         user->ip = NULL;
359         user->realname[0] = 0;
360         user->flags = 0;
361         user->channel = NULL;
362         user->usermode = 0;
363         user->last_who = 0;
364     } else
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);
375     }
376     return user;
377 }
378
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];
382     strcpy(cmask, mask);
383     int i, ii = 0;
384     int already_on_list = 0;
385     struct UserNode *user = NULL;
386     for(i = 0; i < strlen(mask)+1; i++) {
387         if(cmask[i] == '!') {
388             cmask[i] = 0;
389             if(!is_valid_nick(cmask)) {
390                 return NULL;
391             }
392             for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
393                 if(!stricmp(user->nick, cmask)) {
394                     already_on_list = 1;
395                     break;
396                 }
397             }
398             if(!user) {
399                 user = malloc(sizeof(*user));
400                 if (!user) {
401                     perror("malloc() failed");
402                     return NULL;
403                 }
404                 user->ident[0] = 0;
405                 user->host[0] = 0;
406                 user->ip = NULL;
407                 user->realname[0] = 0;
408                 user->flags = 0;
409                 user->channel = NULL;
410                 user->usermode = 0;
411                 user->last_who = 0;
412             } else
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);
418             ii = i+1;
419         } else if(cmask[i] == '.' && !user) {
420             //it's a server
421             user = malloc(sizeof(*user));
422             if (!user)
423             {
424                 perror("malloc() failed");
425                 return NULL;
426             }
427             strcpy(user->host, cmask);
428             strncpy(user->nick, cmask, NICKLEN);
429             user->nick[NICKLEN] = 0;
430             user->created = time(0);
431             user->ident[0] = 0;
432             user->host[0] = 0;
433             user->ip = NULL;
434             user->realname[0] = 0;
435             user->flags = USERFLAG_ISSERVER;
436             user->channel = NULL;
437             user->usermode = 0;
438             user->last_who = 0;
439             break;
440         } else if(cmask[i] == '@') {
441             if(user == NULL) return NULL;
442             cmask[i] = 0;
443             strcpy(user->ident, &cmask[ii]);
444             ii = i+1;
445         } else if(cmask[i] == '\0') {
446             if(user == NULL) {
447                 //nick only
448                 user = malloc(sizeof(*user));
449                 if (!user)
450                 {
451                     perror("malloc() failed");
452                     return NULL;
453                 }
454                 strcpy(user->nick, cmask);
455                 user->created = time(0);
456                 user->ident[0] = 0;
457                 user->host[0] = 0;
458                 user->ip = NULL;
459                 user->realname[0] = 0;
460                 user->flags = 0;
461                 user->channel = NULL;
462                 user->usermode = 0;
463                 user->last_who = 0;
464                 break;
465             }
466             strcpy(user->host, &cmask[ii]);
467         }
468     }
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);
474     }
475     return user;
476 }
477
478 int renameUser(struct UserNode* user, const char *new_nick) {
479     if(!is_valid_nick(new_nick))
480         return 0;
481     if(user->nick[0] == *new_nick) {
482         strcpy(user->nick, new_nick);
483         return 1;
484     }
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) {
492             if(cuser == user) {
493                 if(last_user)
494                     last_user->next = user->next;
495                 else
496                     userList[userListIndex] = user->next;
497                 break;
498             } else
499                 last_user = cuser;
500         }
501     }
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);
507     return 1;
508 }
509
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) {
517         if(cuser == user) {
518             if(last_user)
519                 last_user->next = user->next;
520             else
521                 userList[userListIndex] = user->next;
522             break;
523         } else
524             last_user = cuser;
525     }
526     if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
527         user->flags |= USERFLAG_FREE_AFTER_WHO;
528         freeUser = 0;
529     }
530     if(user->channel) {
531         struct ChanUser *chanUser, *next;
532         for(chanUser = user->channel; chanUser; chanUser = next) {
533             next = chanUser->next_chan;
534             removeChanUserFromLists(chanUser, 1, 0, freeUser);
535         }
536     }
537     if(freeUser) {
538         if(user->ip)
539             freeIPNode(user->ip);
540         free(user);
541     } else
542         user->next = NULL;
543     DESYNCHRONIZE(cache_sync);
544 }
545
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) {
552         next = cuser->next;
553         if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
554             delUser(cuser, 1);
555         }
556     }
557     DESYNCHRONIZE(cache_sync);
558 }