]> jfr.im git - irc/quakenet/newserv.git/blame - nick/nickhandlers.c
TRUSTS: require sqlite
[irc/quakenet/newserv.git] / nick / nickhandlers.c
CommitLineData
c86edd1d
Q
1/* nickhandlers.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 <stdlib.h>
15#include <string.h>
8bab42e7 16#include <stdint.h>
c86edd1d
Q
17
18/*
19 * handlenickmsg:
20 * Handle new nicks being introduced to the network.
21 * Handle renames.
22 */
23
24int handlenickmsg(void *source, int cargc, char **cargv) {
25 char *sender=(char *)source;
26 time_t timestamp;
27 nick *np,*np2;
28 nick **nh;
29 char *fakehost;
30 char *accountts;
c153c0dc 31 char *accountflags;
3a801ca4 32 struct irc_in_addr ipaddress, ipaddress_canonical;
47657339
C
33 char *accountid;
34 unsigned long userid;
c86edd1d
Q
35
36 if (cargc==2) { /* rename */
2fdef282
CP
37 char oldnick[NICKLEN+1];
38 void *harg[2];
39
c86edd1d
Q
40 /* Nyklon 1017697578 */
41 timestamp=strtol(cargv[1],NULL,10);
42 np=getnickbynumericstr(sender);
43 if (np==NULL) {
44 Error("nick",ERR_ERROR,"Rename from non-existent sender %s",sender);
45 return CMD_OK;
46 }
2fdef282
CP
47
48 strncpy(oldnick,np->nick,NICKLEN);
49 oldnick[NICKLEN]='\0';
50 harg[0]=(void *)np;
51 harg[1]=(void *)oldnick;
52
c86edd1d
Q
53 np2=getnickbynick(cargv[0]);
54 if (np==np2) {
55 /* The new and old nickname have the same hash, this means a rename to the same name in
56 * different case, e.g. Flash -> flash. In this case the timestamp for the change should
57 * match the existing timestamp, and we can bypass all the collision checking and hash fettling. */
58 if (np->timestamp!=timestamp) {
16739dbe 59 Error("nick",ERR_WARNING,"Rename to same nickname with different timestamp (%s(%jd) -> %s(%jd))",
58a4da4a 60 np->nick,(intmax_t)np->timestamp,cargv[0], (intmax_t)timestamp);
c86edd1d
Q
61 np->timestamp=timestamp;
62 }
63 strncpy(np->nick,cargv[0],NICKLEN);
64 np->nick[NICKLEN]='\0';
2fdef282 65 triggerhook(HOOK_NICK_RENAME,harg);
c86edd1d
Q
66 return CMD_OK;
67 }
68 if (np2!=NULL) {
69 /* Nick collision */
70 if (ircd_strcmp(np->ident,np2->ident) || (np->host!=np2->host)) {
71 /* Different user@host */
72 if (np2->timestamp < timestamp) {
73 /* The nick attempting to rename got killed. Guess we don't need to do the rename now :) */
74 deletenick(np);
75 return CMD_OK;
76 } else {
77 /* The other nick got killed */
78 deletenick(np2);
79 }
80 } else {
81 if (np2->timestamp < timestamp) {
82 /* Same user@host: reverse logic. Whose idea was all this anyway? */
83 deletenick(np2);
84 } else {
85 deletenick(np);
86 return CMD_OK;
87 }
88 }
89 }
90 /* OK, we've survived the collision hazard. Change timestamp and rename */
91 np->timestamp=timestamp;
92 removenickfromhash(np);
93 strncpy(np->nick,cargv[0],NICKLEN);
94 np->nick[NICKLEN]='\0';
95 addnicktohash(np);
2fdef282 96 triggerhook(HOOK_NICK_RENAME,harg);
c86edd1d
Q
97 } else if (cargc>=8) { /* new nick */
98 /* Jupiler 2 1016645147 ~Jupiler www.iglobal.be +ir moo [FUTURE CRAP HERE] DV74O] BNBd7 :Jupiler */
99 timestamp=strtol(cargv[2],NULL,10);
100 np=getnickbynick(cargv[0]);
101 if (np!=NULL) {
102 /* Nick collision */
103 if (ircd_strcmp(np->ident,cargv[3]) || ircd_strcmp(np->host->name->content,cargv[4])) {
104 /* Different user@host */
105 if (timestamp>np->timestamp) {
106 /* New nick is newer. Ignore this nick message */
107 return CMD_OK;
108 } else {
109 /* New nick is older. Kill the imposter, and drop through */
110 deletenick(np);
111 }
112 } else {
113 if (timestamp>np->timestamp) {
114 /* Same user@host, newer timestamp: we're killing off a ghost */
115 deletenick(np);
116 } else {
117 /* This nick is the ghost, so ignore it */
118 return CMD_OK;
119 }
120 }
121 }
122
123 nh=gethandlebynumeric(numerictolong(cargv[cargc-2],5));
124 if (!nh) {
125 /* This isn't a valid numeric */
126 Error("nick",ERR_WARNING,"Received NICK with invalid numeric %s from %s.",cargv[cargc-2],sender);
127 return CMD_ERROR;
128 }
1a38afd3
P
129
130 base64toip(cargv[cargc-3], &ipaddress);
1a38afd3 131
c86edd1d
Q
132 /* At this stage the nick is cleared to proceed */
133 np=newnick();
134 strncpy(np->nick,cargv[0],NICKLEN);
135 np->nick[NICKLEN]='\0';
136 np->numeric=numerictolong(cargv[cargc-2],5);
137 strncpy(np->ident,cargv[3],USERLEN);
138 np->ident[USERLEN]='\0';
139 np->host=findorcreatehost(cargv[4]);
140 np->realname=findorcreaterealname(cargv[cargc-1]);
141 np->nextbyhost=np->host->nicks;
142 np->host->nicks=np;
143 np->nextbyrealname=np->realname->nicks;
144 np->realname->nicks=np;
145 np->timestamp=timestamp;
526e7c1d 146
3a801ca4
GB
147 memcpy(&(np->ipaddress), &ipaddress, sizeof(ipaddress));
148
4338f313 149 ip_canonicalize_tunnel(&ipaddress_canonical, &ipaddress);
057f5c47 150 np->ipnode = refnode(iptree, &ipaddress_canonical, PATRICIA_MAXBITS);
96644df6 151 node_increment_usercount(np->ipnode);
526e7c1d 152
5144ddc4 153 np->away=NULL;
c86edd1d
Q
154 np->shident=NULL;
155 np->sethost=NULL;
843184e3 156 np->opername=NULL;
c86edd1d
Q
157 np->umodes=0;
158 np->marker=0;
159 memset(np->exts, 0, MAXNICKEXTS * sizeof(void *));
3404a8f0 160 np->authname=NULLAUTHNAME;
47657339 161 np->auth=NULL;
c4ffdb9b 162 np->accountts=0;
42d7af35
GB
163 np->cloak_count = 0;
164 np->cloak_extra = NULL;
c9d54d57 165 np->message = NULL;
c86edd1d 166 if(cargc>=9) {
843184e3
CP
167 int sethostarg = 6, opernamearg = 6, accountarg = 6;
168
c86edd1d 169 setflags(&(np->umodes),UMODE_ALL,cargv[5],umodeflags,REJECT_NONE);
843184e3
CP
170
171 if(IsOper(np) && (serverlist[myhub].flags & SMODE_OPERNAME)) {
172 accountarg++;
173 sethostarg++;
174
175 np->opername=getsstring(cargv[opernamearg],ACCOUNTLEN);
176 }
177
c86edd1d 178 if (IsAccount(np)) {
843184e3
CP
179 sethostarg++;
180
181 if ((accountts=strchr(cargv[accountarg],':'))) {
3404a8f0 182 userid=0;
c86edd1d 183 *accountts++='\0';
3294b10b 184 np->accountts=strtoul(accountts,&accountid,10);
47657339 185 if(accountid) {
c153c0dc 186 userid=strtoul(accountid + 1,&accountflags,10);
3294b10b 187 if(userid) {
843184e3 188 np->auth=findorcreateauthname(userid, cargv[accountarg]);
3294b10b 189 np->authname=np->auth->name;
47657339
C
190 np->auth->usercount++;
191 np->nextbyauthname=np->auth->nicks;
192 np->auth->nicks=np;
0b0fb773 193 if(accountflags)
92acf9ae 194 np->auth->flags=strtoull(accountflags + 1,NULL,10);
47657339 195 }
3404a8f0
CP
196 }
197 if(!userid) {
3294b10b
CP
198 np->authname=malloc(strlen(cargv[accountarg]) + 1);
199 strcpy(np->authname,cargv[accountarg]);
47657339 200 }
c86edd1d 201 }
c86edd1d 202 }
843184e3 203 if (IsSetHost(np) && (fakehost=strchr(cargv[sethostarg],'@'))) {
c86edd1d
Q
204 /* valid sethost */
205 *fakehost++='\0';
843184e3 206 np->shident=getsstring(cargv[sethostarg],USERLEN);
c86edd1d
Q
207 np->sethost=getsstring(fakehost,HOSTLEN);
208 }
209 }
210
211 /* Place this nick in the server nick table. Note that nh is valid from the numeric check above */
212 if (*nh) {
213 /* There was a nick there already -- we have a masked numeric collision
214 * This shouldn't happen, but if it does the newer nick takes precedence
215 * (the two nicks are from the same server, and if the server has reissued
216 * the masked numeric it must believe the old user no longer exists).
217 */
218 Error("nick",ERR_ERROR,"Masked numeric collision for %s [%s vs %s]",cargv[0],cargv[cargc-2],longtonumeric((*nh)->numeric,5));
219 deletenick(*nh);
220 }
221 *nh=np;
222
223 /* And the nick hash table */
224 addnicktohash(np);
225
226 /* Trigger the hook */
227 triggerhook(HOOK_NICK_NEWNICK,np);
228 } else {
229 Error("nick",ERR_WARNING,"Nick message with weird number of parameters (%d)",cargc);
230 }
231
232 return CMD_OK;
233}
234
235int handlequitmsg(void *source, int cargc, char **cargv) {
236 nick *np;
237 void *harg[2];
238
85c382d3 239 if (cargc>0) {
240 harg[1]=(void *)cargv[0];
c86edd1d
Q
241 } else {
242 harg[1]="";
243 }
244
245 np=getnickbynumericstr((char *)source);
246 if (np) {
247 harg[0]=(void *)np;
248 triggerhook(HOOK_NICK_QUIT, harg);
249 deletenick(np);
250 } else {
251 Error("nick",ERR_WARNING,"Quit from non-existant numeric %s",(char *)source);
252 }
253 return CMD_OK;
254}
255
256int handlekillmsg(void *source, int cargc, char **cargv) {
257 nick *np;
acd438c7 258 void *harg[2];
e3073692
CP
259#warning Fix me to use source
260
c86edd1d
Q
261 if (cargc<1) {
262 Error("nick",ERR_WARNING,"Kill message with too few parameters");
263 return CMD_ERROR;
264 }
acd438c7
CP
265
266 if (cargc>1) {
267 harg[1]=(void *)cargv[1];
268 } else {
269 harg[1]="";
270 }
271
c86edd1d
Q
272 np=getnickbynumericstr(cargv[0]);
273 if (np) {
acd438c7
CP
274 harg[0]=(void *)np;
275 triggerhook(HOOK_NICK_KILL, harg);
c86edd1d
Q
276 deletenick(np);
277 } else {
278 Error("nick",ERR_WARNING,"Kill for non-existant numeric %s",cargv[0]);
279 }
280 return CMD_OK;
281}
282
283int handleusermodemsg(void *source, int cargc, char **cargv) {
284 nick *np;
285 flag_t oldflags;
286 char *fakehost;
474d3d62 287 void *args[2];
c86edd1d
Q
288
289 if (cargc<2) {
290 Error("nick",ERR_WARNING,"Mode message with too few parameters");
291 return CMD_LAST; /* With <2 params the channels module won't want it either */
292 }
293
294 if (cargv[0][0]=='#') {
295 /* Channel mode change, we don't care.
296 * We don't bother checking for other channel types here, since & channel mode
297 * changes aren't broadcast and + channels don't have mode changes :) */
298 return CMD_OK;
299 }
300
301 np=getnickbynumericstr((char *)source);
302 if (np!=NULL) {
303 if (ircd_strcmp(cargv[0],np->nick)) {
304 Error("nick",ERR_WARNING,"Attempted mode change on user %s by %s",cargv[0],np->nick);
305 return CMD_OK;
306 }
307 oldflags=np->umodes;
308 setflags(&(np->umodes),UMODE_ALL,cargv[1],umodeflags,REJECT_NONE);
843184e3 309
474d3d62
GB
310 args[0] = np;
311 args[1] = (void *)oldflags;
312 triggerhook(HOOK_NICK_MODECHANGE, args);
313
843184e3
CP
314 if (strchr(cargv[1],'o')) { /* o always comes on its own when being set */
315 if(serverlist[myhub].flags & SMODE_OPERNAME) {
316 if((np->umodes & UMODE_OPER)) {
317 np->opername = getsstring(cargv[2], ACCOUNTLEN);
318 } else {
319 freesstring(np->opername);
1a0e3977 320 np->opername = NULL;
843184e3
CP
321 }
322 }
323 if((np->umodes ^ oldflags) & UMODE_OPER)
324 triggerhook(HOOK_NICK_MODEOPER,np);
325 }
c86edd1d
Q
326 if (strchr(cargv[1],'h')) { /* Have to allow +h twice.. */
327 /* +-h: just the freesstring() calls for the -h case */
328 freesstring(np->shident); /* freesstring(NULL) is OK */
329 freesstring(np->sethost);
330 np->shident=NULL;
331 np->sethost=NULL;
332 if (IsSetHost(np) && cargc>2) { /* +h and mask received */
333 if ((fakehost=strchr(cargv[2],'@'))) {
334 /* user@host change */
335 *fakehost++='\0';
336 np->shident=getsstring(cargv[2],USERLEN);
337 np->sethost=getsstring(fakehost,HOSTLEN);
338 } else {
339 np->sethost=getsstring(cargv[2],HOSTLEN);
340 }
341 }
342 triggerhook(HOOK_NICK_SETHOST, (void *)np);
343 }
344 } else {
345 Error("nick",ERR_WARNING,"Usermode change by unknown user %s",(char *)source);
346 }
347 return CMD_OK;
348}
349
c86edd1d
Q
350int handleaccountmsg(void *source, int cargc, char **cargv) {
351 nick *target;
47657339 352 unsigned long userid;
c4ffdb9b 353 time_t accountts;
6cb1b086 354 u_int64_t accountflags=0, oldflags;
c4ffdb9b
CP
355
356 if (cargc<4) {
c86edd1d
Q
357 return CMD_OK;
358 }
359
360 if ((target=getnickbynumericstr(cargv[0]))==NULL) {
361 return CMD_OK;
362 }
363
c4ffdb9b
CP
364 accountts=strtoul(cargv[2],NULL,10);
365 userid=strtoul(cargv[3],NULL,10);
3294b10b 366 if(cargc>=5)
92acf9ae 367 accountflags=strtoull(cargv[4],NULL,10);
c4ffdb9b
CP
368
369 /* allow user flags to change if all fields match */
c86edd1d 370 if (IsAccount(target)) {
c4ffdb9b
CP
371 void *arg[2];
372
3294b10b 373 if (!target->auth || strcmp(target->auth->name,cargv[1]) || (target->auth->userid != userid) || (target->accountts != accountts)) {
c4ffdb9b
CP
374 return CMD_OK;
375 }
376
92acf9ae
CP
377 oldflags = target->auth->flags;
378 arg[0] = target->auth;
379 arg[1] = &oldflags;
c4ffdb9b
CP
380
381 if (cargc>=5)
382 target->auth->flags=accountflags;
383
384 triggerhook(HOOK_AUTH_FLAGSUPDATED, (void *)arg);
385
c86edd1d
Q
386 return CMD_OK;
387 }
388
389 SetAccount(target);
c4ffdb9b
CP
390 target->accountts=accountts;
391
392 if(!userid) {
47657339 393 target->auth=NULL;
3294b10b
CP
394 target->authname=malloc(strlen(cargv[1]) + 1);
395 strcpy(target->authname,cargv[1]);
c4ffdb9b 396 } else {
5bfb1d14 397 target->auth=findorcreateauthname(userid, cargv[1]);
c4ffdb9b 398 target->auth->usercount++;
3294b10b 399 target->authname=target->auth->name;
c4ffdb9b
CP
400 target->nextbyauthname = target->auth->nicks;
401 target->auth->nicks = target;
402 if (cargc>=5)
403 target->auth->flags=accountflags;
47657339 404 }
c4ffdb9b 405
c86edd1d 406 triggerhook(HOOK_NICK_ACCOUNT, (void *)target);
526e7c1d 407
c86edd1d
Q
408 return CMD_OK;
409}
410
6885ae9c
CP
411int handleprivmsg(void *source, int cargc, char **cargv) {
412 nick *sender;
6885ae9c
CP
413 void *args[3];
414
415 if (cargc<2)
416 return CMD_OK;
417
418 if (cargv[0][0]!='$')
419 return CMD_OK;
420
421 sender=getnickbynumericstr((char *)source);
422
423 if (!match2strings(cargv[0] + 1,myserver->content))
424 return CMD_OK;
425
6885ae9c
CP
426 args[0]=sender;
427 args[1]=cargv[0];
428 args[2]=cargv[1];
429
430 triggerhook(HOOK_NICK_MASKPRIVMSG, (void *)args);
431
432 return CMD_OK;
433}
434
5144ddc4 435int handleawaymsg(void *source, int cargc, char **cargv) {
436 nick *sender;
437
438 /* Check source is a valid user */
439 if (!(sender=getnickbynumericstr(source))) {
440 return CMD_OK;
441 }
442
443 /* Done with the old away message either way */
444 freesstring(sender->away);
445 sender->away=NULL;
446
447 /* If we have an arg and it isn't an empty string, this sets a new message */
448 if (cargc > 0 && *(cargv[0])) {
449 sender->away=getsstring(cargv[0], AWAYLEN);
450 }
451
452 return CMD_OK;
453}
42d7af35
GB
454
455int handleaddcloak(void *source, int cargc, char **cargv) {
456 nick *sender, *target;
457
458 /* Check source is a valid user */
459 if (!(sender=getnickbynumericstr(source))) {
460 return CMD_OK;
461 }
462
463 if (cargc < 1)
464 return CMD_OK;
465
466 if (!(target=getnickbynumericstr(cargv[0]))) {
467 return CMD_OK;
468 }
469
470 addcloaktarget(sender, target);
471
472 return CMD_OK;
473}
474
475int handleclearcloak(void *source, int cargc, char **cargv) {
476 nick *sender;
477
478 /* Check source is a valid user */
479 if (!(sender=getnickbynumericstr(source))) {
480 return CMD_OK;
481 }
482
483 clearcloaktargets(sender);
484
485 return CMD_OK;
486}
487