added cmd_trace and cmd_wipeinfo
[NeonServV5.git] / UserNode.c
1 #include "UserNode.h"
2 #include "ChanUser.h"
3 #include "tools.h"
4
5 static struct UserNode **userList;
6
7 void init_UserNode() {
8     userList = calloc(VALID_NICK_CHARS_FIRST_LEN+1, sizeof(*userList));
9 }
10
11 void free_UserNode() {
12     //kamikaze free all users
13     //chanusers will be destroyed in free_ChanNode()
14     int i;
15     struct UserNode *user, *next;
16     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
17         for(user = userList[i]; user; user = next) {
18             next = user->next;
19             free(user);
20         }
21     }
22     free(userList);
23 }
24
25 int is_valid_nick(const char *nick) {
26     unsigned int i;
27     //first char must be one of: a-zA-Z{|}~[\]^_`
28     if (!strchr(VALID_NICK_CHARS_FIRST, *nick))
29         return 0;
30     //all other chars must be one of: a-zA-Z0-9{|}~[\]^_`
31     for (i = 0; nick[i]; ++i)
32         if (!strchr(VALID_NICK_CHARS, nick[i]))
33             return 0;
34     if (strlen(nick) > NICKLEN)
35         return 0;
36     return 1;
37 }
38
39 static int get_nicklist_entry(int nick) {
40     int i;
41     char *valid_chars = VALID_NICK_CHARS_FIRST;
42     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN; i++) {
43         if(valid_chars[i] == nick)
44             return i;
45     }
46     return -1; //ERROR!
47 }
48
49 struct UserNode* getUserByNick(const char *nick) { //case sensitive
50     int userListIndex = get_nicklist_entry(*nick);
51     if(userListIndex == -1 || userList[userListIndex] == NULL)
52         return NULL;
53     struct UserNode *user;
54     for(user = userList[userListIndex]; user; user = user->next) {
55         if(!stricmp(nick, user->nick))
56             return user;
57     }
58     return NULL;
59 }
60
61 struct UserNode* getUserByMask(const char *mask) { //case sensitive
62     char cmask[strlen(mask)+1];
63     strcpy(cmask, mask);
64     int i;
65     struct UserNode *user = NULL;
66     for(i = 0; i < strlen(mask); i++) {
67         if(cmask[i] == '!') {
68             cmask[i] = 0;
69             user = getUserByNick(&cmask[0]);
70             return user;
71         } else if(cmask[i] == '.') {
72             //it's a server
73             return NULL;
74         }
75     }
76     return NULL;
77 }
78
79 struct UserNode* searchUserByNick(const char *nick) { //case insensitive
80     if(!isalpha(*nick)) 
81         return getUserByNick(nick);
82
83     int userListIndex;
84     struct UserNode *user;
85
86     //search in the lower case "section"
87     userListIndex = get_nicklist_entry(tolower(*nick));
88     if(userListIndex != -1 && userList[userListIndex] != NULL) {
89         for(user = userList[userListIndex]; user; user = user->next) {
90             if(!stricmp(nick, user->nick))
91                 return user;
92         }
93     }
94     //search in the upper case "section"
95     userListIndex = get_nicklist_entry(toupper(*nick));
96     if(userListIndex != -1 && userList[userListIndex] != NULL) {
97         for(user = userList[userListIndex]; user; user = user->next) {
98             if(!stricmp(nick, user->nick))
99                 return user;
100         }
101     }
102     return NULL;
103 }
104
105 int countUsersWithHost(char *host) {
106     int i, count = 0;
107     struct UserNode *user;
108     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
109         for(user = userList[i]; user; user = user->next) {
110             if(!strcmp(user->host, host)) {
111                 count++;
112             }
113         }
114     }
115     return count;
116 }
117
118 char *getAuthFakehost(char *auth) {
119     int i;
120     struct UserNode *user;
121     for(i = 0; i < VALID_NICK_CHARS_FIRST_LEN+1; i++) {
122         for(user = userList[i]; user; user = user->next) {
123             if((user->flags & USERFLAG_ISAUTHED) && !strcmp(user->auth, auth) && isFakeHost(user->host)) {
124                 return user->host;
125             }
126         }
127     }
128     return NULL;
129 }
130
131 struct UserNode* getAllUsers(struct UserNode *last) {
132     if(last == NULL || last->next == NULL) {
133         int cindex;
134         if(last == NULL)
135             cindex = 0;
136         else
137             cindex = get_nicklist_entry(last->nick[0]) + 1;
138         while(userList[cindex] == NULL && cindex <= VALID_NICK_CHARS_FIRST_LEN)
139             cindex++;
140         if(cindex > VALID_NICK_CHARS_FIRST_LEN) return NULL;
141         return userList[cindex];
142     } else
143         return last->next;
144 }
145
146 struct UserNode* addUser(const char *nick) {
147     int userListIndex = get_nicklist_entry(*nick);
148     if(userListIndex == -1 || !is_valid_nick(nick))
149         return NULL;
150     struct UserNode *user = malloc(sizeof(*user));
151     if (!user)
152     {
153         perror("malloc() failed");
154         return NULL;
155     }
156     strcpy(user->nick, nick);
157     user->created = time(0);
158     user->ident[0] = 0;
159     user->host[0] = 0;
160     user->realname[0] = 0;
161     user->flags = 0;
162     user->channel = NULL;
163     user->next = userList[userListIndex];
164     userList[userListIndex] = user;
165     return user;
166 }
167
168 struct UserNode* addUserMask(const char *mask) {
169     char cmask[strlen(mask)+1];
170     strcpy(cmask, mask);
171     int i, ii = 0;
172     struct UserNode *user = NULL;
173     for(i = 0; i < strlen(mask)+1; i++) {
174         if(cmask[i] == '!') {
175             cmask[i] = 0;
176             user = addUser(cmask);
177             if(user == NULL) return NULL;
178             ii = i+1;
179         } else if(cmask[i] == '.' && !user) {
180             //it's a server
181             return NULL;
182         } else if(cmask[i] == '@') {
183             if(user == NULL) return NULL;
184             cmask[i] = 0;
185             strcpy(user->ident, &cmask[ii]);
186             ii = i+1;
187         } else if(cmask[i] == '\0') {
188             if(user == NULL) return NULL;
189             strcpy(user->host, &cmask[ii]);
190         }
191     }
192     return user;
193 }
194
195 struct UserNode* createTempUser(const char *mask) {
196     //note: it could also be a server we have to create a temponary user for...
197     char cmask[strlen(mask)+1];
198     strcpy(cmask, mask);
199     int i, ii = 0;
200     struct UserNode *user = NULL;
201     for(i = 0; i < strlen(mask)+1; i++) {
202         if(cmask[i] == '!') {
203             cmask[i] = 0;
204             user = malloc(sizeof(*user));
205             if (!user)
206             {
207                 perror("malloc() failed");
208                 return NULL;
209             }
210             strcpy(user->nick, cmask);
211             user->created = time(0);
212             user->ident[0] = 0;
213             user->host[0] = 0;
214             user->realname[0] = 0;
215             user->flags = 0;
216             user->channel = NULL;
217             ii = i+1;
218         } else if(cmask[i] == '.' && !user) {
219             //it's a server
220             user = malloc(sizeof(*user));
221             if (!user)
222             {
223                 perror("malloc() failed");
224                 return NULL;
225             }
226             strcpy(user->host, cmask);
227             user->created = time(0);
228             user->ident[0] = 0;
229             user->host[0] = 0;
230             user->realname[0] = 0;
231             user->flags = USERFLAG_ISSERVER;
232             user->channel = NULL;
233             return user;
234         } else if(cmask[i] == '@') {
235             if(user == NULL) return NULL;
236             cmask[i] = 0;
237             strcpy(user->ident, &cmask[ii]);
238             ii = i+1;
239         } else if(cmask[i] == '\0') {
240             if(user == NULL) {
241                 //nick only
242                 user = malloc(sizeof(*user));
243                 if (!user)
244                 {
245                     perror("malloc() failed");
246                     return NULL;
247                 }
248                 strcpy(user->nick, cmask);
249                 user->created = time(0);
250                 user->ident[0] = 0;
251                 user->host[0] = 0;
252                 user->realname[0] = 0;
253                 user->flags = 0;
254                 user->channel = NULL;
255                 return user;
256             }
257             strcpy(user->host, &cmask[ii]);
258         }
259     }
260     return user;
261 }
262
263 int renameUser(struct UserNode* user, const char *new_nick) {
264     if(!is_valid_nick(new_nick))
265         return 0;
266     if(user->nick[0] == *new_nick) {
267         strcpy(user->nick, new_nick);
268         return 1;
269     }
270     int userListIndex = get_nicklist_entry(*new_nick);
271     delUser(user, 0);
272     strcpy(user->nick, new_nick);
273     user->next = userList[userListIndex];
274     userList[userListIndex] = user;
275     return 1;
276 }
277
278 void delUser(struct UserNode* user, int freeUser) {
279     int userListIndex = get_nicklist_entry(user->nick[0]);
280     if(userListIndex == -1) return;
281     struct UserNode *cuser, *last_user = NULL;
282     for(cuser = userList[userListIndex]; cuser; cuser = cuser->next) {
283         if(cuser == user) {
284             if(last_user)
285                 last_user->next = user->next;
286             else
287                 userList[userListIndex] = user->next;
288             break;
289         } else
290             last_user = cuser;
291     }
292     if(user->channel) {
293         struct ChanUser *chanUser, *next;
294         for(chanUser = user->channel; chanUser; chanUser = next) {
295             next = chanUser->next_chan;
296             removeChanUserFromLists(chanUser, 1, 0, freeUser);
297         }
298     }
299     if(freeUser)
300         free(user);
301     else
302         user->next = NULL;
303 }
304
305 void clearTempUsers() {
306     int userListIndex = TEMPUSER_LIST_INDEX;
307     struct UserNode *cuser, *last_user = NULL, *next;
308     time_t now = time(0);
309     for(cuser = userList[userListIndex]; cuser; cuser = next) {
310         next = cuser->next;
311         if(cuser->flags & USERFLAG_FREETMPUSER || now - cuser->created >= 300) {
312             if(last_user)
313                 last_user->next = cuser->next;
314             else
315                 userList[userListIndex] = cuser->next;
316             break;
317         } else
318             last_user = cuser;
319     }
320 }