]>
jfr.im git - irc/quakenet/newserv.git/blob - nick/nickhandlers.c
8426bb7c4eec431bbc122dcc9431a9fb554d5507
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"
20 * Handle new nicks being introduced to the network.
24 int handlenickmsg(void *source
, int cargc
, char **cargv
) {
25 char *sender
=(char *)source
;
32 struct irc_in_addr ipaddress
;
36 if (cargc
==2) { /* rename */
37 char oldnick
[NICKLEN
+1];
40 /* Nyklon 1017697578 */
41 timestamp
=strtol(cargv
[1],NULL
,10);
42 np
=getnickbynumericstr(sender
);
44 Error("nick",ERR_ERROR
,"Rename from non-existent sender %s",sender
);
48 strncpy(oldnick
,np
->nick
,NICKLEN
);
49 oldnick
[NICKLEN
]='\0';
51 harg
[1]=(void *)oldnick
;
53 np2
=getnickbynick(cargv
[0]);
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
) {
59 Error("nick",ERR_WARNING
,"Rename to same nickname with different timestamp (%s(%jd) -> %s(%jd))",
60 np
->nick
,(intmax_t)np
->timestamp
,cargv
[0], (intmax_t)timestamp
);
61 np
->timestamp
=timestamp
;
63 strncpy(np
->nick
,cargv
[0],NICKLEN
);
64 np
->nick
[NICKLEN
]='\0';
65 triggerhook(HOOK_NICK_RENAME
,harg
);
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 :) */
77 /* The other nick got killed */
81 if (np2
->timestamp
< timestamp
) {
82 /* Same user@host: reverse logic. Whose idea was all this anyway? */
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';
96 triggerhook(HOOK_NICK_RENAME
,harg
);
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]);
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 */
109 /* New nick is older. Kill the imposter, and drop through */
113 if (timestamp
>np
->timestamp
) {
114 /* Same user@host, newer timestamp: we're killing off a ghost */
117 /* This nick is the ghost, so ignore it */
123 nh
=gethandlebynumeric(numerictolong(cargv
[cargc
-2],5));
125 /* This isn't a valid numeric */
126 Error("nick",ERR_WARNING
,"Received NICK with invalid numeric %s from %s.",cargv
[cargc
-2],sender
);
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
);
136 /* At this stage the nick is cleared to proceed */
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
;
147 np
->nextbyrealname
=np
->realname
->nicks
;
148 np
->realname
->nicks
=np
;
149 np
->timestamp
=timestamp
;
151 base64toip(cargv
[cargc
-3], &ipaddress
);
152 np
->ipnode
= refnode(iptree
, &ipaddress
, PATRICIA_MAXBITS
);
153 node_increment_usercount(np
->ipnode
);
161 memset(np
->exts
, 0, MAXNICKEXTS
* sizeof(void *));
162 np
->authname
=NULLAUTHNAME
;
166 int sethostarg
= 6, opernamearg
= 6, accountarg
= 6;
168 setflags(&(np
->umodes
),UMODE_ALL
,cargv
[5],umodeflags
,REJECT_NONE
);
170 if(IsOper(np
) && (serverlist
[myhub
].flags
& SMODE_OPERNAME
)) {
174 np
->opername
=getsstring(cargv
[opernamearg
],ACCOUNTLEN
);
180 if ((accountts
=strchr(cargv
[accountarg
],':'))) {
183 np
->accountts
=strtoul(accountts
,&accountid
,10);
185 userid
=strtoul(accountid
+ 1,&accountflags
,10);
187 np
->auth
=findorcreateauthname(userid
, cargv
[accountarg
]);
188 np
->authname
=np
->auth
->name
;
189 np
->auth
->usercount
++;
190 np
->nextbyauthname
=np
->auth
->nicks
;
193 np
->auth
->flags
=strtoull(accountflags
+ 1,NULL
,10);
197 np
->authname
=malloc(strlen(cargv
[accountarg
]) + 1);
198 strcpy(np
->authname
,cargv
[accountarg
]);
202 if (IsSetHost(np
) && (fakehost
=strchr(cargv
[sethostarg
],'@'))) {
205 np
->shident
=getsstring(cargv
[sethostarg
],USERLEN
);
206 np
->sethost
=getsstring(fakehost
,HOSTLEN
);
210 /* Place this nick in the server nick table. Note that nh is valid from the numeric check above */
212 /* There was a nick there already -- we have a masked numeric collision
213 * This shouldn't happen, but if it does the newer nick takes precedence
214 * (the two nicks are from the same server, and if the server has reissued
215 * the masked numeric it must believe the old user no longer exists).
217 Error("nick",ERR_ERROR
,"Masked numeric collision for %s [%s vs %s]",cargv
[0],cargv
[cargc
-2],longtonumeric((*nh
)->numeric
,5));
222 /* And the nick hash table */
225 /* Trigger the hook */
226 triggerhook(HOOK_NICK_NEWNICK
,np
);
228 Error("nick",ERR_WARNING
,"Nick message with weird number of parameters (%d)",cargc
);
234 int handlequitmsg(void *source
, int cargc
, char **cargv
) {
239 harg
[1]=(void *)cargv
[0];
244 np
=getnickbynumericstr((char *)source
);
247 triggerhook(HOOK_NICK_QUIT
, harg
);
250 Error("nick",ERR_WARNING
,"Quit from non-existant numeric %s",(char *)source
);
255 int handlekillmsg(void *source
, int cargc
, char **cargv
) {
258 #warning Fix me to use source
261 Error("nick",ERR_WARNING
,"Kill message with too few parameters");
266 harg
[1]=(void *)cargv
[1];
271 np
=getnickbynumericstr(cargv
[0]);
274 triggerhook(HOOK_NICK_KILL
, harg
);
277 Error("nick",ERR_WARNING
,"Kill for non-existant numeric %s",cargv
[0]);
282 int handleusermodemsg(void *source
, int cargc
, char **cargv
) {
288 Error("nick",ERR_WARNING
,"Mode message with too few parameters");
289 return CMD_LAST
; /* With <2 params the channels module won't want it either */
292 if (cargv
[0][0]=='#') {
293 /* Channel mode change, we don't care.
294 * We don't bother checking for other channel types here, since & channel mode
295 * changes aren't broadcast and + channels don't have mode changes :) */
299 np
=getnickbynumericstr((char *)source
);
301 if (ircd_strcmp(cargv
[0],np
->nick
)) {
302 Error("nick",ERR_WARNING
,"Attempted mode change on user %s by %s",cargv
[0],np
->nick
);
306 setflags(&(np
->umodes
),UMODE_ALL
,cargv
[1],umodeflags
,REJECT_NONE
);
308 if (strchr(cargv
[1],'o')) { /* o always comes on its own when being set */
309 if(serverlist
[myhub
].flags
& SMODE_OPERNAME
) {
310 if((np
->umodes
& UMODE_OPER
)) {
311 np
->opername
= getsstring(cargv
[2], ACCOUNTLEN
);
313 freesstring(np
->opername
);
317 if((np
->umodes
^ oldflags
) & UMODE_OPER
)
318 triggerhook(HOOK_NICK_MODEOPER
,np
);
320 if (strchr(cargv
[1],'h')) { /* Have to allow +h twice.. */
321 /* +-h: just the freesstring() calls for the -h case */
322 freesstring(np
->shident
); /* freesstring(NULL) is OK */
323 freesstring(np
->sethost
);
326 if (IsSetHost(np
) && cargc
>2) { /* +h and mask received */
327 if ((fakehost
=strchr(cargv
[2],'@'))) {
328 /* user@host change */
330 np
->shident
=getsstring(cargv
[2],USERLEN
);
331 np
->sethost
=getsstring(fakehost
,HOSTLEN
);
333 np
->sethost
=getsstring(cargv
[2],HOSTLEN
);
336 triggerhook(HOOK_NICK_SETHOST
, (void *)np
);
339 Error("nick",ERR_WARNING
,"Usermode change by unknown user %s",(char *)source
);
344 int handleaccountmsg(void *source
, int cargc
, char **cargv
) {
346 unsigned long userid
;
348 u_int64_t accountflags
=0, oldflags
;
354 if ((target
=getnickbynumericstr(cargv
[0]))==NULL
) {
358 accountts
=strtoul(cargv
[2],NULL
,10);
359 userid
=strtoul(cargv
[3],NULL
,10);
361 accountflags
=strtoull(cargv
[4],NULL
,10);
363 /* allow user flags to change if all fields match */
364 if (IsAccount(target
)) {
367 if (!target
->auth
|| strcmp(target
->auth
->name
,cargv
[1]) || (target
->auth
->userid
!= userid
) || (target
->accountts
!= accountts
)) {
371 oldflags
= target
->auth
->flags
;
372 arg
[0] = target
->auth
;
376 target
->auth
->flags
=accountflags
;
378 triggerhook(HOOK_AUTH_FLAGSUPDATED
, (void *)arg
);
384 target
->accountts
=accountts
;
388 target
->authname
=malloc(strlen(cargv
[1]) + 1);
389 strcpy(target
->authname
,cargv
[1]);
391 target
->auth
=findorcreateauthname(userid
, cargv
[1]);
392 target
->auth
->usercount
++;
393 target
->authname
=target
->auth
->name
;
394 target
->nextbyauthname
= target
->auth
->nicks
;
395 target
->auth
->nicks
= target
;
397 target
->auth
->flags
=accountflags
;
400 triggerhook(HOOK_NICK_ACCOUNT
, (void *)target
);
405 int handleprivmsg(void *source
, int cargc
, char **cargv
) {
413 if (cargv
[0][0]!='$')
416 sender
=getnickbynumericstr((char *)source
);
418 if (!match2strings(cargv
[0] + 1,myserver
->content
))
427 triggerhook(HOOK_NICK_MASKPRIVMSG
, (void *)args
);
432 int handleawaymsg(void *source
, int cargc
, char **cargv
) {
435 /* Check source is a valid user */
436 if (!(sender
=getnickbynumericstr(source
))) {
440 /* Done with the old away message either way */
441 freesstring(sender
->away
);
444 /* If we have an arg and it isn't an empty string, this sets a new message */
445 if (cargc
> 0 && *(cargv
[0])) {
446 sender
->away
=getsstring(cargv
[0], AWAYLEN
);