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