]> jfr.im git - irc/quakenet/newserv.git/blame - nick/nickhandlers.c
Merge default.
[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);
131 if (!irc_in_addr_valid(&ipaddress)) {
132 Error("nick",ERR_ERROR,"Received NICK with invalid ipaddress for %s from %s.",cargv[0],sender);
133 return CMD_ERROR;
134 }
135
c86edd1d
Q
136 /* At this stage the nick is cleared to proceed */
137 np=newnick();
138 strncpy(np->nick,cargv[0],NICKLEN);
139 np->nick[NICKLEN]='\0';
140 np->numeric=numerictolong(cargv[cargc-2],5);
141 strncpy(np->ident,cargv[3],USERLEN);
142 np->ident[USERLEN]='\0';
143 np->host=findorcreatehost(cargv[4]);
144 np->realname=findorcreaterealname(cargv[cargc-1]);
145 np->nextbyhost=np->host->nicks;
146 np->host->nicks=np;
147 np->nextbyrealname=np->realname->nicks;
148 np->realname->nicks=np;
149 np->timestamp=timestamp;
526e7c1d 150
3a801ca4
GB
151 memcpy(&(np->ipaddress), &ipaddress, sizeof(ipaddress));
152
4338f313 153 ip_canonicalize_tunnel(&ipaddress_canonical, &ipaddress);
3a801ca4 154 np->ipnode = refnode(iptree, &ipaddress_canonical, irc_in_addr_is_ipv4(&ipaddress) ? 128 : 64);
96644df6 155 node_increment_usercount(np->ipnode);
526e7c1d 156
5144ddc4 157 np->away=NULL;
c86edd1d
Q
158 np->shident=NULL;
159 np->sethost=NULL;
843184e3 160 np->opername=NULL;
c86edd1d
Q
161 np->umodes=0;
162 np->marker=0;
163 memset(np->exts, 0, MAXNICKEXTS * sizeof(void *));
3404a8f0 164 np->authname=NULLAUTHNAME;
47657339 165 np->auth=NULL;
c4ffdb9b 166 np->accountts=0;
c86edd1d 167 if(cargc>=9) {
843184e3
CP
168 int sethostarg = 6, opernamearg = 6, accountarg = 6;
169
c86edd1d 170 setflags(&(np->umodes),UMODE_ALL,cargv[5],umodeflags,REJECT_NONE);
843184e3
CP
171
172 if(IsOper(np) && (serverlist[myhub].flags & SMODE_OPERNAME)) {
173 accountarg++;
174 sethostarg++;
175
176 np->opername=getsstring(cargv[opernamearg],ACCOUNTLEN);
177 }
178
c86edd1d 179 if (IsAccount(np)) {
843184e3
CP
180 sethostarg++;
181
182 if ((accountts=strchr(cargv[accountarg],':'))) {
3404a8f0 183 userid=0;
c86edd1d 184 *accountts++='\0';
3294b10b 185 np->accountts=strtoul(accountts,&accountid,10);
47657339 186 if(accountid) {
c153c0dc 187 userid=strtoul(accountid + 1,&accountflags,10);
3294b10b 188 if(userid) {
843184e3 189 np->auth=findorcreateauthname(userid, cargv[accountarg]);
3294b10b 190 np->authname=np->auth->name;
47657339
C
191 np->auth->usercount++;
192 np->nextbyauthname=np->auth->nicks;
193 np->auth->nicks=np;
0b0fb773 194 if(accountflags)
92acf9ae 195 np->auth->flags=strtoull(accountflags + 1,NULL,10);
47657339 196 }
3404a8f0
CP
197 }
198 if(!userid) {
3294b10b
CP
199 np->authname=malloc(strlen(cargv[accountarg]) + 1);
200 strcpy(np->authname,cargv[accountarg]);
47657339 201 }
c86edd1d 202 }
c86edd1d 203 }
843184e3 204 if (IsSetHost(np) && (fakehost=strchr(cargv[sethostarg],'@'))) {
c86edd1d
Q
205 /* valid sethost */
206 *fakehost++='\0';
843184e3 207 np->shident=getsstring(cargv[sethostarg],USERLEN);
c86edd1d
Q
208 np->sethost=getsstring(fakehost,HOSTLEN);
209 }
210 }
211
212 /* Place this nick in the server nick table. Note that nh is valid from the numeric check above */
213 if (*nh) {
214 /* There was a nick there already -- we have a masked numeric collision
215 * This shouldn't happen, but if it does the newer nick takes precedence
216 * (the two nicks are from the same server, and if the server has reissued
217 * the masked numeric it must believe the old user no longer exists).
218 */
219 Error("nick",ERR_ERROR,"Masked numeric collision for %s [%s vs %s]",cargv[0],cargv[cargc-2],longtonumeric((*nh)->numeric,5));
220 deletenick(*nh);
221 }
222 *nh=np;
223
224 /* And the nick hash table */
225 addnicktohash(np);
226
227 /* Trigger the hook */
228 triggerhook(HOOK_NICK_NEWNICK,np);
229 } else {
230 Error("nick",ERR_WARNING,"Nick message with weird number of parameters (%d)",cargc);
231 }
232
233 return CMD_OK;
234}
235
236int handlequitmsg(void *source, int cargc, char **cargv) {
237 nick *np;
238 void *harg[2];
239
85c382d3 240 if (cargc>0) {
241 harg[1]=(void *)cargv[0];
c86edd1d
Q
242 } else {
243 harg[1]="";
244 }
245
246 np=getnickbynumericstr((char *)source);
247 if (np) {
248 harg[0]=(void *)np;
249 triggerhook(HOOK_NICK_QUIT, harg);
250 deletenick(np);
251 } else {
252 Error("nick",ERR_WARNING,"Quit from non-existant numeric %s",(char *)source);
253 }
254 return CMD_OK;
255}
256
257int handlekillmsg(void *source, int cargc, char **cargv) {
258 nick *np;
acd438c7 259 void *harg[2];
e3073692
CP
260#warning Fix me to use source
261
c86edd1d
Q
262 if (cargc<1) {
263 Error("nick",ERR_WARNING,"Kill message with too few parameters");
264 return CMD_ERROR;
265 }
acd438c7
CP
266
267 if (cargc>1) {
268 harg[1]=(void *)cargv[1];
269 } else {
270 harg[1]="";
271 }
272
c86edd1d
Q
273 np=getnickbynumericstr(cargv[0]);
274 if (np) {
acd438c7
CP
275 harg[0]=(void *)np;
276 triggerhook(HOOK_NICK_KILL, harg);
c86edd1d
Q
277 deletenick(np);
278 } else {
279 Error("nick",ERR_WARNING,"Kill for non-existant numeric %s",cargv[0]);
280 }
281 return CMD_OK;
282}
283
284int handleusermodemsg(void *source, int cargc, char **cargv) {
285 nick *np;
286 flag_t oldflags;
287 char *fakehost;
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
CP
309
310 if (strchr(cargv[1],'o')) { /* o always comes on its own when being set */
311 if(serverlist[myhub].flags & SMODE_OPERNAME) {
312 if((np->umodes & UMODE_OPER)) {
313 np->opername = getsstring(cargv[2], ACCOUNTLEN);
314 } else {
315 freesstring(np->opername);
1a0e3977 316 np->opername = NULL;
843184e3
CP
317 }
318 }
319 if((np->umodes ^ oldflags) & UMODE_OPER)
320 triggerhook(HOOK_NICK_MODEOPER,np);
321 }
c86edd1d
Q
322 if (strchr(cargv[1],'h')) { /* Have to allow +h twice.. */
323 /* +-h: just the freesstring() calls for the -h case */
324 freesstring(np->shident); /* freesstring(NULL) is OK */
325 freesstring(np->sethost);
326 np->shident=NULL;
327 np->sethost=NULL;
328 if (IsSetHost(np) && cargc>2) { /* +h and mask received */
329 if ((fakehost=strchr(cargv[2],'@'))) {
330 /* user@host change */
331 *fakehost++='\0';
332 np->shident=getsstring(cargv[2],USERLEN);
333 np->sethost=getsstring(fakehost,HOSTLEN);
334 } else {
335 np->sethost=getsstring(cargv[2],HOSTLEN);
336 }
337 }
338 triggerhook(HOOK_NICK_SETHOST, (void *)np);
339 }
340 } else {
341 Error("nick",ERR_WARNING,"Usermode change by unknown user %s",(char *)source);
342 }
343 return CMD_OK;
344}
345
c86edd1d
Q
346int handleaccountmsg(void *source, int cargc, char **cargv) {
347 nick *target;
47657339 348 unsigned long userid;
c4ffdb9b 349 time_t accountts;
6cb1b086 350 u_int64_t accountflags=0, oldflags;
c4ffdb9b
CP
351
352 if (cargc<4) {
c86edd1d
Q
353 return CMD_OK;
354 }
355
356 if ((target=getnickbynumericstr(cargv[0]))==NULL) {
357 return CMD_OK;
358 }
359
c4ffdb9b
CP
360 accountts=strtoul(cargv[2],NULL,10);
361 userid=strtoul(cargv[3],NULL,10);
3294b10b 362 if(cargc>=5)
92acf9ae 363 accountflags=strtoull(cargv[4],NULL,10);
c4ffdb9b
CP
364
365 /* allow user flags to change if all fields match */
c86edd1d 366 if (IsAccount(target)) {
c4ffdb9b
CP
367 void *arg[2];
368
3294b10b 369 if (!target->auth || strcmp(target->auth->name,cargv[1]) || (target->auth->userid != userid) || (target->accountts != accountts)) {
c4ffdb9b
CP
370 return CMD_OK;
371 }
372
92acf9ae
CP
373 oldflags = target->auth->flags;
374 arg[0] = target->auth;
375 arg[1] = &oldflags;
c4ffdb9b
CP
376
377 if (cargc>=5)
378 target->auth->flags=accountflags;
379
380 triggerhook(HOOK_AUTH_FLAGSUPDATED, (void *)arg);
381
c86edd1d
Q
382 return CMD_OK;
383 }
384
385 SetAccount(target);
c4ffdb9b
CP
386 target->accountts=accountts;
387
388 if(!userid) {
47657339 389 target->auth=NULL;
3294b10b
CP
390 target->authname=malloc(strlen(cargv[1]) + 1);
391 strcpy(target->authname,cargv[1]);
c4ffdb9b 392 } else {
5bfb1d14 393 target->auth=findorcreateauthname(userid, cargv[1]);
c4ffdb9b 394 target->auth->usercount++;
3294b10b 395 target->authname=target->auth->name;
c4ffdb9b
CP
396 target->nextbyauthname = target->auth->nicks;
397 target->auth->nicks = target;
398 if (cargc>=5)
399 target->auth->flags=accountflags;
47657339 400 }
c4ffdb9b 401
c86edd1d 402 triggerhook(HOOK_NICK_ACCOUNT, (void *)target);
526e7c1d 403
c86edd1d
Q
404 return CMD_OK;
405}
406
6885ae9c
CP
407int handleprivmsg(void *source, int cargc, char **cargv) {
408 nick *sender;
409 char *message;
410 void *args[3];
411
412 if (cargc<2)
413 return CMD_OK;
414
415 if (cargv[0][0]!='$')
416 return CMD_OK;
417
418 sender=getnickbynumericstr((char *)source);
419
420 if (!match2strings(cargv[0] + 1,myserver->content))
421 return CMD_OK;
422
423 message=cargv[0];
424
425 args[0]=sender;
426 args[1]=cargv[0];
427 args[2]=cargv[1];
428
429 triggerhook(HOOK_NICK_MASKPRIVMSG, (void *)args);
430
431 return CMD_OK;
432}
433
5144ddc4 434int handleawaymsg(void *source, int cargc, char **cargv) {
435 nick *sender;
436
437 /* Check source is a valid user */
438 if (!(sender=getnickbynumericstr(source))) {
439 return CMD_OK;
440 }
441
442 /* Done with the old away message either way */
443 freesstring(sender->away);
444 sender->away=NULL;
445
446 /* If we have an arg and it isn't an empty string, this sets a new message */
447 if (cargc > 0 && *(cargv[0])) {
448 sender->away=getsstring(cargv[0], AWAYLEN);
449 }
450
451 return CMD_OK;
452}