]> jfr.im git - irc/quakenet/newserv.git/blob - nick/nick.c
2b949d971f4e872adda4db9a73c13b66a440e1e5
[irc/quakenet/newserv.git] / nick / nick.c
1 /* nick.c */
2
3 #include "nick.h"
4 #include "../lib/flags.h"
5 #include "../lib/irc_string.h"
6 #include "../lib/base64.h"
7 #include "../irc/irc.h"
8 #include "../irc/irc_config.h"
9 #include "../core/error.h"
10 #include "../core/hooks.h"
11 #include "../lib/sstring.h"
12 #include "../server/server.h"
13 #include "../parser/parser.h"
14 #include "../lib/version.h"
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18
19 MODULE_VERSION("");
20
21 const flag umodeflags[] = {
22 { 'i', UMODE_INV },
23 { 'w', UMODE_WALLOPS },
24 { 'g', UMODE_DEBUG },
25 { 'o', UMODE_OPER },
26 { 'k', UMODE_SERVICE },
27 { 'X', UMODE_XOPER },
28 { 'd', UMODE_DEAF },
29 { 'r', UMODE_ACCOUNT },
30 { 'n', UMODE_HIDECHAN },
31 { 'x', UMODE_HIDEHOST },
32 { 'h', UMODE_SETHOST },
33 { 'R', UMODE_REGPRIV },
34 { 'I', UMODE_HIDEIDLE },
35 { '\0', 0 } };
36
37 #define nickhash(x) ((crc32i(x))%NICKHASHSIZE)
38
39 nick *nicktable[NICKHASHSIZE];
40 nick **servernicks[MAXSERVERS];
41
42 sstring *nickextnames[MAXNICKEXTS];
43 sstring *nodeextnames[PATRICIA_MAXSLOTS];
44 patricia_tree_t *iptree;
45 sstring *authnameextnames[MAXAUTHNAMEEXTS];
46
47 void nickstats(int hooknum, void *arg);
48
49 void _init() {
50 initnickalloc();
51 initnickhelpers();
52 memset(nicktable,0,sizeof(nicktable));
53 memset(servernicks,0,sizeof(servernicks));
54
55 /* Register our hooks */
56 registerhook(HOOK_SERVER_NEWSERVER,&handleserverchange);
57 registerhook(HOOK_SERVER_LOSTSERVER,&handleserverchange);
58 registerhook(HOOK_CORE_STATSREQUEST,&nickstats);
59
60 /* And our server handlers */
61 registerserverhandler("N",&handlenickmsg,10);
62 registerserverhandler("D",&handlekillmsg,2);
63 registerserverhandler("Q",&handlequitmsg,1);
64 registerserverhandler("M",&handleusermodemsg,3);
65 registerserverhandler("W",&handlewhoismsg,2);
66 registerserverhandler("AC",&handleaccountmsg,4);
67 registerserverhandler("R",&handlestatsmsg,2);
68
69 /* Fake the addition of our own server */
70 handleserverchange(HOOK_SERVER_NEWSERVER,(void *)numerictolong(mynumeric->content,2));
71
72 iptree = patricia_new_tree(PATRICIA_MAXBITS);
73 }
74
75 /*
76 * This function handles servers appearing and disappearing.
77 * For a new server, the client table is allocated.
78 * For a disappearing server, all it's clients are killed and the client table is freed.
79 */
80
81 void handleserverchange(int hooknum, void *arg) {
82 long servernum;
83 int i;
84
85 servernum=(long)arg;
86
87 switch(hooknum) {
88 case HOOK_SERVER_NEWSERVER:
89 servernicks[servernum]=(nick **)malloc((serverlist[servernum].maxusernum+1)*sizeof(nick **));
90 memset(servernicks[servernum],0,(serverlist[servernum].maxusernum+1)*sizeof(nick **));
91 break;
92
93 case HOOK_SERVER_LOSTSERVER:
94 for (i=0;i<=serverlist[servernum].maxusernum;i++) {
95 if (servernicks[servernum][i]!=NULL) {
96 deletenick(servernicks[servernum][i]);
97 }
98 }
99 free(servernicks[servernum]);
100 break;
101 }
102 }
103
104 /*
105 * deletenick:
106 *
107 * This function handles the removal of a nick from the network
108 */
109
110 void deletenick(nick *np) {
111 nick **nh;
112
113 /* Fire the hook. This will deal with removal from channels etc. */
114 triggerhook(HOOK_NICK_LOSTNICK, np);
115
116 /* Release the realname and hostname parts */
117
118 for (nh=&(np->realname->nicks);*nh;nh=&((*nh)->nextbyrealname)) {
119 if (*nh==np) {
120 *nh=np->nextbyrealname;
121 break;
122 }
123 }
124
125 for (nh=&(np->host->nicks);*nh;nh=&((*nh)->nextbyhost)) {
126 if (*nh==np) {
127 *nh=np->nextbyhost;
128 break;
129 }
130 }
131
132 releaserealname(np->realname);
133 releasehost(np->host);
134
135 if(IsAccount(np) && np->auth)
136 {
137 np->auth->usercount--;
138
139 for (nh=&(np->auth->nicks);*nh;nh=&((*nh)->nextbyauthname)) {
140 if (*nh==np) {
141 *nh=np->nextbyauthname;
142 break;
143 }
144 }
145
146 releaseauthname(np->auth);
147 }
148
149 freesstring(np->shident); /* freesstring(NULL) is OK */
150 freesstring(np->sethost);
151
152 derefnode(iptree, np->ipnode);
153
154 /* TODO: figure out how to cleanly remove nodes without affecting other modules */
155
156 /* Delete the nick from the servernick table */
157 *(gethandlebynumericunsafe(np->numeric))=NULL;
158
159 /* Remove the nick from the hash table */
160 removenickfromhash(np);
161
162 freenick(np);
163 }
164
165 void addnicktohash(nick *np) {
166 np->next=nicktable[nickhash(np->nick)];
167 nicktable[nickhash(np->nick)]=np;
168 }
169
170 void removenickfromhash(nick *np) {
171 nick **nh;
172
173 for (nh=&(nicktable[nickhash(np->nick)]);*nh;nh=&((*nh)->next)) {
174 if ((*nh)==np) {
175 (*nh)=np->next;
176 break;
177 }
178 }
179 }
180
181 nick *getnickbynick(const char *name) {
182 nick *np;
183
184 for (np=nicktable[nickhash(name)];np;np=np->next) {
185 if (!ircd_strcmp(np->nick,name))
186 return np;
187 }
188
189 return NULL;
190 }
191
192 void nickstats(int hooknum, void *arg) {
193 int total,maxchain,curchain,i,buckets;
194 nick *np;
195 char buf[200];
196
197 /* Get nick stats */
198 buckets=total=maxchain=curchain=0;
199 for (i=0;i<NICKHASHSIZE;i++,curchain=0) {
200 np=nicktable[i];
201 if (np!=NULL) {
202 buckets++;
203 for (;np;np=np->next) {
204 total++;
205 curchain++;
206 }
207 }
208 if (curchain>maxchain) {
209 maxchain=curchain;
210 }
211 }
212
213 if ((long)arg>5) {
214 /* Full stats */
215 sprintf(buf,"Nick : %6d nicks (HASH: %6d/%6d, chain %3d)",total,buckets,NICKHASHSIZE,maxchain);
216 } else if ((long)arg>2) {
217 sprintf(buf,"Nick : %6d users on network.",total);
218 }
219
220 if ((long)arg>2) {
221 triggerhook(HOOK_CORE_STATSREPLY,buf);
222 }
223 }
224
225 int registernickext(const char *name) {
226 int i;
227
228 if (findnickext(name)!=-1) {
229 Error("nick",ERR_WARNING,"Tried to register duplicate nick extension %s",name);
230 return -1;
231 }
232
233 for (i=0;i<MAXNICKEXTS;i++) {
234 if (nickextnames[i]==NULL) {
235 nickextnames[i]=getsstring(name,100);
236 return i;
237 }
238 }
239
240 Error("nick",ERR_WARNING,"Tried to register too many nick extensions: %s",name);
241 return -1;
242 }
243
244 int findnickext(const char *name) {
245 int i;
246
247 for (i=0;i<MAXNICKEXTS;i++) {
248 if (nickextnames[i]!=NULL && !ircd_strcmp(name,nickextnames[i]->content)) {
249 return i;
250 }
251 }
252
253 return -1;
254 }
255
256 void releasenickext(int index) {
257 int i;
258 nick *np;
259
260 freesstring(nickextnames[index]);
261 nickextnames[index]=NULL;
262
263 for (i=0;i<NICKHASHSIZE;i++) {
264 for (np=nicktable[i];np;np=np->next) {
265 np->exts[index]=NULL;
266 }
267 }
268 }
269
270 int registerauthnameext(const char *name) {
271 int i;
272
273 if (findauthnameext(name)!=-1) {
274 Error("nick",ERR_WARNING,"Tried to register duplicate authname extension %s",name);
275 return -1;
276 }
277
278 for (i=0;i<MAXAUTHNAMEEXTS;i++) {
279 if (authnameextnames[i]==NULL) {
280 authnameextnames[i]=getsstring(name,100);
281 return i;
282 }
283 }
284
285 Error("nick",ERR_WARNING,"Tried to register too many authname extensions: %s",name);
286 return -1;
287 }
288
289 int findauthnameext(const char *name) {
290 int i;
291
292 for (i=0;i<MAXAUTHNAMEEXTS;i++) {
293 if (authnameextnames[i]!=NULL && !ircd_strcmp(name,authnameextnames[i]->content)) {
294 return i;
295 }
296 }
297
298 return -1;
299 }
300
301 void releaseauthnameext(int index) {
302 int i;
303 authname *anp;
304
305 freesstring(authnameextnames[index]);
306 authnameextnames[index]=NULL;
307
308 for (i=0;i<AUTHNAMEHASHSIZE;i++) {
309 for (anp=authnametable[i];anp;anp=anp->next) {
310 anp->exts[index]=NULL;
311 }
312 }
313 }
314
315 /* visiblehostmask
316 * Produces the "apparent" hostmask as seen by network users.
317 */
318
319 char *visiblehostmask(nick *np, char *buf) {
320 char hostbuf[HOSTLEN+1];
321 char *ident, *host;
322
323 ident=np->ident;
324 host=np->host->name->content;
325
326 if (IsSetHost(np)) {
327 if (np->shident) {
328 ident=np->shident->content;
329 }
330 if (np->sethost) {
331 host=np->sethost->content;
332 }
333 } else if (IsAccount(np) && IsHideHost(np)) {
334 sprintf(hostbuf,"%s.%s", np->authname, HIS_HIDDENHOST);
335 host=hostbuf;
336 }
337
338 sprintf(buf,"%s!%s@%s",np->nick,ident,host);
339
340 return buf;
341 }
342
343 #if 0
344
345 /*
346 * gethandlebynumeric:
347 * Given a numeric, gives the location in the servernicks table
348 * where it should be. Does not check that the nick currently found
349 * there (if any) has the correct numeric; this is left to the
350 * calling function to figure out.
351 */
352
353 nick **gethandlebynumeric(long numeric) {
354 int servernum;
355 int maskednum;
356 server *serv;
357
358 /* Shift off the client identifier part of the numeric to get the server ID */
359 servernum=(numeric>>18);
360
361 if ((serv=getserverdata(servernum))==NULL) {
362 Error("nick",ERR_WARNING,"Numeric %ld refers to non-existent server %d",numeric,servernum);
363 return NULL;
364 }
365
366 /* Compute the masked numeric */
367 maskednum=numeric&(serv->maxusernum);
368
369 return (servernicks[servernum])+maskednum;
370 }
371
372 /*
373 * getnickbynumeric[str]()
374 * These functions retrieve a nick based on it's numeric on the network
375 * Use the approriate function depending on how your numeric is expressed..
376 */
377
378 nick *getnickbynumeric(long numeric) {
379 nick **nh;
380
381 nh=gethandlebynumeric(numeric);
382
383 if ((*nh) && ((*nh)->numeric!=numeric)) {
384 /* We found a masked numeric match, but the actual numeric
385 * is different. This counts as a miss. */
386 return NULL;
387 }
388
389 return (*nh);
390 }
391
392 nick *getnickbynumericstr(char *numericstr) {
393 return getnickbynumeric(numerictolong(numericstr,5));
394 }
395
396 #endif
397
398 int registernodeext(const char *name) {
399 int i;
400
401 if (findnodeext(name)!=-1) {
402 Error("nick",ERR_WARNING,"Tried to register duplicate node extension %s",name);
403 return -1;
404 }
405
406 for (i=0;i<PATRICIA_MAXSLOTS;i++) {
407 if (nodeextnames[i]==NULL) {
408 nodeextnames[i]=getsstring(name,100);
409 return i;
410 }
411 }
412
413 Error("nick",ERR_WARNING,"Tried to register too many extensions: %s",name);
414 return -1;
415 }
416
417 int findnodeext(const char *name) {
418 int i;
419
420 for (i=0;i<PATRICIA_MAXSLOTS;i++) {
421 if (nodeextnames[i]!=NULL && !ircd_strcmp(name,nodeextnames[i]->content)) {
422 return i;
423 }
424 }
425
426 return -1;
427 }
428
429 void releasenodeext(int index) {
430 patricia_node_t *head, *node;
431
432 freesstring(nodeextnames[index]);
433 nodeextnames[index]=NULL;
434
435 head = iptree->head;
436
437 PATRICIA_WALK_ALL(head, node)
438 {
439 node->slots[index]=NULL;
440 } PATRICIA_WALK_END;
441 }