21b618d1118b51a16fac594e638f44976378ba6b
[NeonServV5.git] / src / UserNode.c
1 /* UserNode.c - NeonServ v5.3
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 "ChanUser.h"
19 #include "tools.h"
20 #include "IRCEvents.h"
21 #include "IPNode.h"
22
23 static struct UserNode **userList;
24
25 void init_UserNode() {
26     userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
27 }
28
29 void free_UserNode() {
30     //kamikaze free all users
31     //chanusers will be destroyed in free_ChanNode()
32     int i;
33     struct UserNode *user, *next;
34     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
35         for(user = userList[i]; user; user = next) {
36             next = user->next;
37             free(user);
38         }
39     }
40     free(userList);
41 }
42
43 int is_valid_nick(const char *nick) {
44     unsigned int i;
45     //first char must be one of: a-zA-Z{|}~[\]^_`
46     if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
47         return 0;
48     //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
49     for (i = 0; nick[i]; ++i)
50         if (!strchr(VALID_NICK_CHARS, nick[i]))
51             return 0;
52     if (strlen(nick) > NICKLEN)
53         return 0;
54     return 1;
55 }
56
57 static int get_nicklist_entry(int nick) {
58     int i;
59     char *valid_chars = VALID_NICK_CHARS_FIRST;
60     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
61         if(valid_chars[i] == nick)
62             return i;
63     }
64     return -1; //ERROR!
65 }
66
67 struct UserNode* getUserByNick(const char *nick) { //case sensitive
68     int userListIndex = get_nicklist_entry(*nick);
69     if(userListIndex == -1 || userList[userListIndex] == NULL)
70         return NULL;
71     struct UserNode *user;
72     for(user = userList[userListIndex]; user; user = user->next) {
73         if(!stricmp(nick, user->nick))
74             return user;
75     }
76     return NULL;
77 }
78
79 struct UserNode* getUserByMask(const char *mask) { //case sensitive
80     char cmask[strlen(mask)+1];
81     strcpy(cmask, mask);
82     int i;
83     struct UserNode *user = NULL;
84     for(i = 0; i < strlen(mask); i++) {
85         if(cmask[i] == '!') {
86             cmask[i] = 0;
87             user = getUserByNick(&cmask[0]);
88             return user;
89         } else if(cmask[i] == '.') {
90             //it's a server
91             return NULL;
92         }
93     }
94     return NULL;
95 }
96
97 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
98     if(!isalpha(*nick)) 
99         return getUserByNick(nick);
100
101     int userListIndex;
102     struct UserNode *user;
103
104     //search in the lower case "section"
105     userListIndex = get_nicklist_entry(tolower(*nick));
106     if(userListIndex != -1 && userList[userListIndex] != NULL) {
107         for(user = userList[userListIndex]; user; user = user->next) {
108             if(!stricmp(nick, user->nick))
109                 return user;
110         }
111     }
112     //search in the upper case "section"
113     userListIndex = get_nicklist_entry(toupper(*nick));
114     if(userListIndex != -1 && userList[userListIndex] != NULL) {
115         for(user = userList[userListIndex]; user; user = user->next) {
116             if(!stricmp(nick, user->nick))
117                 return user;
118         }
119     }
120     return NULL;
121 }
122
123 int countUsersWithHost(char *host) {
124     int i, count = 0;
125     struct UserNode *user;
126     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
127         for(user = userList[i]; user; user = user->next) {
128             if(!strcmp(user->host, host)) {
129                 count++;
130             }
131         }
132     }
133     return count;
134 }
135
136 char *getAuthFakehost(char *auth) {
137     int i;
138     struct UserNode *user;
139     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
140         for(user = userList[i]; user; user = user->next) {
141             if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
142                 return user->host;
143             }
144         }
145     }
146     return NULL;
147 }
148
149 struct UserNode* getAllUsers(struct UserNode *last) {
150     if(last == NULL || last->next == NULL) {
151         int cindex;
152         if(last == NULL)
153             cindex = 0;
154         else
155             cindex = get_nicklist_entry(last->nick[0]) + 1;
156         while(userList[cindex] == NULL && cindex < VALID_NICK_CHARS_FIRST_LEN)
157             cindex++;
158         if(cindex > VALID_NICK_CHARS_FIRST_LEN) return NULL;
159         return userList[cindex];
160     } else
161         return last->next;
162 }
163
164 struct UserNode* getUsersWithAuth(const char *auth, struct UserNode *last) {
165     int cindex = (last ? get_nicklist_entry(last->nick[0]) : 0);
166     struct UserNode *cuser = last;
167     while(cindex <= VALID_NICK_CHARS_FIRST_LEN) {
168         for(cuser = (cuser ? cuser->next : userList[cindex]); cuser; cuser = cuser->next) {
169             if((cuser->flags & USERFLAG_ISAUTHED) && !strcmp(cuser->auth, auth))
170                 return cuser;
171         }
172         cindex++;
173         cuser = NULL;
174     }
175     return NULL;
176 }
177
178 int getUserCount() {
179     int i, count = 0;
180     struct UserNode *user;
181     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
182         for(user = userList[i]; user; user = user->next) {
183             count++;
184         }
185     }
186     return count;
187 }
188
189 struct UserNode* addUser(const char *nick) {
190     int userListIndex = get_nicklist_entry(*nick);
191     if(userListIndex == -1 || !is_valid_nick(nick))
192         return NULL;
193     struct UserNode *user = malloc(sizeof(*user));
194     if (!user)
195     {
196         perror("malloc() failed");
197         return NULL;
198     }
199     strcpy(user->nick, nick);
200     user->created = time(0);
201     user->ident[0] = 0;
202     user->host[0] = 0;
203     user->ip = NULL;
204     user->realname[0] = 0;
205     user->flags = 0;
206     user->channel = NULL;
207     user->last_who = 0;
208     user->next = userList[userListIndex];
209     userList[userListIndex] = user;
210     return user;
211 }
212
213 struct UserNode* addUserMask(const char *mask) {
214     char cmask[strlen(mask)+1];
215     strcpy(cmask, mask);
216     int i, ii = 0;
217     struct UserNode *user = NULL;
218     for(i = 0; i < strlen(mask)+1; i++) {
219         if(cmask[i] == '!') {
220             cmask[i] = 0;
221             user = addUser(cmask);
222             if(user == NULL) return NULL;
223             ii = i+1;
224         } else if(cmask[i] == '.' && !user) {
225             //it's a server
226             return NULL;
227         } else if(cmask[i] == '@') {
228             if(user == NULL) return NULL;
229             cmask[i] = 0;
230             strcpy(user->ident, &cmask[ii]);
231             ii = i+1;
232         } else if(cmask[i] == '\0') {
233             if(user == NULL) return NULL;
234             strcpy(user->host, &cmask[ii]);
235         }
236     }
237     return user;
238 }
239
240 struct UserNode* createTempUser(const char *nick) {
241     int already_on_list = 0;
242     struct UserNode *user = NULL;
243     if(!is_valid_nick(nick)) {
244         return NULL;
245     }
246     for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
247         if(!stricmp(user->nick, nick)) {
248             already_on_list = 1;
249             break;
250         }
251     }
252     if(!user) {
253         user = malloc(sizeof(*user));
254         if (!user) {
255             perror("malloc() failed");
256             return NULL;
257         }
258         user->ident[0] = 0;
259         user->host[0] = 0;
260         user->ip = NULL;
261         user->realname[0] = 0;
262         user->flags = 0;
263         user->channel = NULL;
264         user->last_who = 0;
265     } else
266         user->flags &= ~USERFLAG_FREETMPUSER;
267     user->created = time(0);
268     if(user->created - user->last_who > REWHO_TIMEOUT)
269         user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
270     strcpy(user->nick, nick);
271     if(!already_on_list) {
272         user->next = userList[TEMPUSER_LIST_INDEX];
273         userList[TEMPUSER_LIST_INDEX] = user;
274     }
275     return user;
276 }
277
278 struct UserNode* createTempUserMask(const char *mask) {
279     //note: it could also be a server we have to create a temponary user for...
280     char cmask[strlen(mask)+1];
281     strcpy(cmask, mask);
282     int i, ii = 0;
283     int already_on_list = 0;
284     struct UserNode *user = NULL;
285     for(i = 0; i < strlen(mask)+1; i++) {
286         if(cmask[i] == '!') {
287             cmask[i] = 0;
288             if(!is_valid_nick(cmask)) {
289                 return NULL;
290             }
291             for(user = userList[TEMPUSER_LIST_INDEX]; user; user = user->next) {
292                 if(!stricmp(user->nick, cmask)) {
293                     already_on_list = 1;
294                     break;
295                 }
296             }
297             if(!user) {
298                 user = malloc(sizeof(*user));
299                 if (!user) {
300                     perror("malloc() failed");
301                     return NULL;
302                 }
303                 user->ident[0] = 0;
304                 user->host[0] = 0;
305                 user->ip = NULL;
306                 user->realname[0] = 0;
307                 user->flags = 0;
308                 user->channel = NULL;
309                 user->last_who = 0;
310             } else
311                 user->flags &= ~USERFLAG_FREETMPUSER;
312             user->created = time(0);
313             if(user->created - user->last_who > REWHO_TIMEOUT)
314                 user->flags &= ~USERFLAG_ISAUTHED; //remove authed flag (security reasons)
315             strcpy(user->nick, cmask);
316             ii = i+1;
317         } else if(cmask[i] == '.' && !user) {
318             //it's a server
319             user = malloc(sizeof(*user));
320             if (!user)
321             {
322                 perror("malloc() failed");
323                 return NULL;
324             }
325             strcpy(user->host, cmask);
326             user->created = time(0);
327             user->ident[0] = 0;
328             user->host[0] = 0;
329             user->ip = NULL;
330             user->realname[0] = 0;
331             user->flags = USERFLAG_ISSERVER;
332             user->channel = NULL;
333             user->last_who = 0;
334             return user;
335         } else if(cmask[i] == '@') {
336             if(user == NULL) return NULL;
337             cmask[i] = 0;
338             strcpy(user->ident, &cmask[ii]);
339             ii = i+1;
340         } else if(cmask[i] == '\0') {
341             if(user == NULL) {
342                 //nick only
343                 user = malloc(sizeof(*user));
344                 if (!user)
345                 {
346                     perror("malloc() failed");
347                     return NULL;
348                 }
349                 strcpy(user->nick, cmask);
350                 user->created = time(0);
351                 user->ident[0] = 0;
352                 user->host[0] = 0;
353                 user->ip = NULL;
354                 user->realname[0] = 0;
355                 user->flags = 0;
356                 user->channel = NULL;
357                 user->last_who = 0;
358                 break;
359             }
360             strcpy(user->host, &cmask[ii]);
361         }
362     }
363     if(!already_on_list) {
364         user->next = userList[TEMPUSER_LIST_INDEX];
365         userList[TEMPUSER_LIST_INDEX] = user;
366     }
367     return user;
368 }
369
370 int renameUser(struct UserNode* user, const char *new_nick) {
371     if(!is_valid_nick(new_nick))
372         return 0;
373     if(user->nick[0] == *new_nick) {
374         strcpy(user->nick, new_nick);
375         return 1;
376     }
377     //delUser(user, 0); //EPIC FAIL! This deletes the user from the channel Userlist -.-
378     //manually remove the user from the old userList
379     int userListIndex = get_nicklist_entry(user->nick[0]);
380     if(userListIndex != -1) {
381         struct UserNode *cuser, *last_user = NULL;
382         for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
383             if(cuser == user) {
384                 if(last_user)
385                     last_user->next = user->next;
386                 else
387                     userList[userListIndex] = user->next;
388                 break;
389             } else
390                 last_user = cuser;
391         }
392     }
393     userListIndex = get_nicklist_entry(*new_nick);
394     strcpy(user->nick, new_nick);
395     user->next = userList[userListIndex];
396     userList[userListIndex] = user;
397     return 1;
398 }
399
400 void delUser(struct UserNode* user, int freeUser) {
401     int userListIndex = ((user->flags & USERFLAG_ISTMPUSER) ? TEMPUSER_LIST_INDEX : get_nicklist_entry(user->nick[0]));
402     if(userListIndex == -1) return;
403     event_freeuser(user);
404     struct UserNode *cuser, *last_user = NULL;
405     for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
406         if(cuser == user) {
407             if(last_user)
408                 last_user->next = user->next;
409             else
410                 userList[userListIndex] = user->next;
411             break;
412         } else
413             last_user = cuser;
414     }
415     if(freeUser && (user->flags & USERFLAG_IS_ON_WHO_QUEUE)) {
416         user->flags |= USERFLAG_FREE_AFTER_WHO;
417         freeUser = 0;
418     }
419     if(user->channel) {
420         struct ChanUser *chanUser, *next;
421         for(chanUser = user->channel; chanUser; chanUser = next) {
422             next = chanUser->next_chan;
423             removeChanUserFromLists(chanUser, 1, 0, freeUser);
424         }
425     }
426     if(freeUser) {
427         if(user->ip)
428             freeIPNode(user->ip);
429         free(user);
430     } else
431         user->next = NULL;
432 }
433
434 void clearTempUsers() {
435     int userListIndex = TEMPUSER_LIST_INDEX;
436     struct UserNode *cuser, *next;
437     time_t now = time(0);
438     for(cuser = userList[userListIndex]; cuser; cuser = next) {
439         next = cuser->next;
440         if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
441             delUser(cuser, 1);
442         }
443     }
444 }