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