]>
jfr.im git - irc/quakenet/newserv.git/blob - nick/nickhandlers.c
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"
19 * Handle new nicks being introduced to the network.
23 int handlenickmsg(void *source
, int cargc
, char **cargv
) {
24 char *sender
=(char *)source
;
31 if (cargc
==2) { /* rename */
32 /* Nyklon 1017697578 */
33 timestamp
=strtol(cargv
[1],NULL
,10);
34 np
=getnickbynumericstr(sender
);
36 Error("nick",ERR_ERROR
,"Rename from non-existent sender %s",sender
);
39 np2
=getnickbynick(cargv
[0]);
41 /* The new and old nickname have the same hash, this means a rename to the same name in
42 * different case, e.g. Flash -> flash. In this case the timestamp for the change should
43 * match the existing timestamp, and we can bypass all the collision checking and hash fettling. */
44 if (np
->timestamp
!=timestamp
) {
45 Error("nick",ERR_WARNING
,"Rename to same nickname with different timestamp (%s(%d) -> %s(%d))",
46 np
->nick
,np
->timestamp
,cargv
[0],timestamp
);
47 np
->timestamp
=timestamp
;
49 strncpy(np
->nick
,cargv
[0],NICKLEN
);
50 np
->nick
[NICKLEN
]='\0';
51 triggerhook(HOOK_NICK_RENAME
,np
);
56 if (ircd_strcmp(np
->ident
,np2
->ident
) || (np
->host
!=np2
->host
)) {
57 /* Different user@host */
58 if (np2
->timestamp
< timestamp
) {
59 /* The nick attempting to rename got killed. Guess we don't need to do the rename now :) */
63 /* The other nick got killed */
67 if (np2
->timestamp
< timestamp
) {
68 /* Same user@host: reverse logic. Whose idea was all this anyway? */
76 /* OK, we've survived the collision hazard. Change timestamp and rename */
77 np
->timestamp
=timestamp
;
78 removenickfromhash(np
);
79 strncpy(np
->nick
,cargv
[0],NICKLEN
);
80 np
->nick
[NICKLEN
]='\0';
82 triggerhook(HOOK_NICK_RENAME
,np
);
83 } else if (cargc
>=8) { /* new nick */
84 /* Jupiler 2 1016645147 ~Jupiler www.iglobal.be +ir moo [FUTURE CRAP HERE] DV74O] BNBd7 :Jupiler */
85 timestamp
=strtol(cargv
[2],NULL
,10);
86 np
=getnickbynick(cargv
[0]);
89 if (ircd_strcmp(np
->ident
,cargv
[3]) || ircd_strcmp(np
->host
->name
->content
,cargv
[4])) {
90 /* Different user@host */
91 if (timestamp
>np
->timestamp
) {
92 /* New nick is newer. Ignore this nick message */
95 /* New nick is older. Kill the imposter, and drop through */
99 if (timestamp
>np
->timestamp
) {
100 /* Same user@host, newer timestamp: we're killing off a ghost */
103 /* This nick is the ghost, so ignore it */
109 nh
=gethandlebynumeric(numerictolong(cargv
[cargc
-2],5));
111 /* This isn't a valid numeric */
112 Error("nick",ERR_WARNING
,"Received NICK with invalid numeric %s from %s.",cargv
[cargc
-2],sender
);
116 /* At this stage the nick is cleared to proceed */
118 strncpy(np
->nick
,cargv
[0],NICKLEN
);
119 np
->nick
[NICKLEN
]='\0';
120 np
->numeric
=numerictolong(cargv
[cargc
-2],5);
121 strncpy(np
->ident
,cargv
[3],USERLEN
);
122 np
->ident
[USERLEN
]='\0';
123 np
->host
=findorcreatehost(cargv
[4]);
124 np
->realname
=findorcreaterealname(cargv
[cargc
-1]);
125 np
->nextbyhost
=np
->host
->nicks
;
127 np
->nextbyrealname
=np
->realname
->nicks
;
128 np
->realname
->nicks
=np
;
129 np
->timestamp
=timestamp
;
130 np
->ipaddress
=numerictolong(cargv
[cargc
-3],6);
135 memset(np
->exts
, 0, MAXNICKEXTS
* sizeof(void *));
136 np
->authname
[0]='\0';
138 setflags(&(np
->umodes
),UMODE_ALL
,cargv
[5],umodeflags
,REJECT_NONE
);
140 if ((accountts
=strchr(cargv
[6],':'))) {
142 np
->accountts
=strtoul(accountts
,NULL
,10);
146 strncpy(np
->authname
,cargv
[6],ACCOUNTLEN
);
147 np
->authname
[ACCOUNTLEN
]='\0';
149 if (IsSetHost(np
) && (fakehost
=strchr(cargv
[cargc
-4],'@'))) {
152 np
->shident
=getsstring(cargv
[cargc
-4],USERLEN
);
153 np
->sethost
=getsstring(fakehost
,HOSTLEN
);
157 /* Place this nick in the server nick table. Note that nh is valid from the numeric check above */
159 /* There was a nick there already -- we have a masked numeric collision
160 * This shouldn't happen, but if it does the newer nick takes precedence
161 * (the two nicks are from the same server, and if the server has reissued
162 * the masked numeric it must believe the old user no longer exists).
164 Error("nick",ERR_ERROR
,"Masked numeric collision for %s [%s vs %s]",cargv
[0],cargv
[cargc
-2],longtonumeric((*nh
)->numeric
,5));
169 /* And the nick hash table */
172 /* Trigger the hook */
173 triggerhook(HOOK_NICK_NEWNICK
,np
);
175 Error("nick",ERR_WARNING
,"Nick message with weird number of parameters (%d)",cargc
);
181 int handlequitmsg(void *source
, int cargc
, char **cargv
) {
186 harg
[1]=(void *)cargv
[1];
191 np
=getnickbynumericstr((char *)source
);
194 triggerhook(HOOK_NICK_QUIT
, harg
);
197 Error("nick",ERR_WARNING
,"Quit from non-existant numeric %s",(char *)source
);
202 int handlekillmsg(void *source
, int cargc
, char **cargv
) {
206 Error("nick",ERR_WARNING
,"Kill message with too few parameters");
209 np
=getnickbynumericstr(cargv
[0]);
213 Error("nick",ERR_WARNING
,"Kill for non-existant numeric %s",cargv
[0]);
218 int handleusermodemsg(void *source
, int cargc
, char **cargv
) {
224 Error("nick",ERR_WARNING
,"Mode message with too few parameters");
225 return CMD_LAST
; /* With <2 params the channels module won't want it either */
228 if (cargv
[0][0]=='#') {
229 /* Channel mode change, we don't care.
230 * We don't bother checking for other channel types here, since & channel mode
231 * changes aren't broadcast and + channels don't have mode changes :) */
235 np
=getnickbynumericstr((char *)source
);
237 if (ircd_strcmp(cargv
[0],np
->nick
)) {
238 Error("nick",ERR_WARNING
,"Attempted mode change on user %s by %s",cargv
[0],np
->nick
);
242 if (strchr(cargv
[1],'o')) {
246 triggerhook(HOOK_NICK_MODEOPER
,harg
);
248 setflags(&(np
->umodes
),UMODE_ALL
,cargv
[1],umodeflags
,REJECT_NONE
);
249 if (strchr(cargv
[1],'h')) { /* Have to allow +h twice.. */
250 /* +-h: just the freesstring() calls for the -h case */
251 freesstring(np
->shident
); /* freesstring(NULL) is OK */
252 freesstring(np
->sethost
);
255 if (IsSetHost(np
) && cargc
>2) { /* +h and mask received */
256 if ((fakehost
=strchr(cargv
[2],'@'))) {
257 /* user@host change */
259 np
->shident
=getsstring(cargv
[2],USERLEN
);
260 np
->sethost
=getsstring(fakehost
,HOSTLEN
);
262 np
->sethost
=getsstring(cargv
[2],HOSTLEN
);
265 triggerhook(HOOK_NICK_SETHOST
, (void *)np
);
268 Error("nick",ERR_WARNING
,"Usermode change by unknown user %s",(char *)source
);
273 int handlewhoismsg(void *source
, int cargc
, char **cargv
) {
274 nick
*sender
,*target
;
280 if (strncmp(cargv
[0],mynumeric
->content
,2)) {
284 /* Find the sender... */
285 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
286 Error("localuser",ERR_WARNING
,"WHOIS message from non existent numeric %s",(char *)source
);
290 /* :hub.splidge.netsplit.net 311 moo splidge splidge ground.stbarnab.as * :splidge
291 :hub.splidge.netsplit.net 312 moo splidge splidge.netsplit.net :splidge's netsplit leaf
292 :hub.splidge.netsplit.net 313 moo splidge :is an IRC Operator
293 :hub.splidge.netsplit.net 318 moo splidge :End of /WHOIS list.
296 /* And the target... */
297 if ((target
=getnickbynick(cargv
[1]))==NULL
) {
298 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[1]);
300 irc_send(":%s 311 %s %s %s %s * :%s",myserver
->content
,sender
->nick
,target
->nick
,target
->ident
,
301 target
->host
->name
->content
, target
->realname
->name
->content
);
302 nicks
[0]=sender
; nicks
[1]=target
;
303 triggerhook(HOOK_NICK_WHOISCHANNELS
,nicks
);
304 if (IsOper(sender
) || !HIS_SERVER
) {
305 irc_send(":%s 312 %s %s %s :%s",myserver
->content
,sender
->nick
,target
->nick
,
306 serverlist
[homeserver(target
->numeric
)].name
->content
,
307 serverlist
[homeserver(target
->numeric
)].description
->content
);
309 irc_send(":%s 312 %s %s " HIS_SERVERNAME
" :" HIS_SERVERDESC
,myserver
->content
,sender
->nick
,target
->nick
);
311 if (IsOper(target
)) {
312 irc_send(":%s 313 %s %s :is an IRC Operator",myserver
->content
,sender
->nick
,target
->nick
);
314 if (IsAccount(target
)) {
315 irc_send(":%s 330 %s %s %s :is logged in as",myserver
->content
,sender
->nick
,target
->nick
,target
->authname
);
317 if (homeserver(target
->numeric
)==mylongnum
&& !IsService(target
)) {
318 irc_send(":%s 317 %s %s %ld %ld :seconds idle, signon time",myserver
->content
,sender
->nick
,target
->nick
,
319 0,target
->timestamp
);
323 irc_send(":%s 318 %s %s :End of /WHOIS list.",myserver
->content
,sender
->nick
,cargv
[1]);
327 int handleaccountmsg(void *source
, int cargc
, char **cargv
) {
334 if ((target
=getnickbynumericstr(cargv
[0]))==NULL
) {
338 if (IsAccount(target
)) {
343 strncpy(target
->authname
,cargv
[1],ACCOUNTLEN
);
344 target
->authname
[ACCOUNTLEN
]='\0';
346 triggerhook(HOOK_NICK_ACCOUNT
, (void *)target
);
351 int handlestatsmsg(void *source
, int cargc
, char **cargv
) {
353 char *sender
=(char *)source
;
359 Error("nick",ERR_WARNING
,"STATS request without enough parameters!");
363 if (strlen(sender
)==5) {
365 np
=getnickbynumericstr(sender
);
367 Error("nick",ERR_WARNING
,"STATS request from unknown client %s",sender
);
370 replytarget
=np
->nick
;
372 Error("nick",ERR_WARNING
,"STATS request from odd source %s",sender
);
376 /* Reply to stats for ANY server.. including any we are juping */
377 sourceserver
=numerictolong(cargv
[1],2);
378 if (serverlist
[sourceserver
].maxusernum
==0) {
379 Error("nick",ERR_WARNING
,"Stats request for bad server %s",cargv
[1]);
382 fromstring
=serverlist
[sourceserver
].name
->content
;
384 switch(cargv
[0][0]) {
386 irc_send(":%s 242 %s :Server Up %s",fromstring
,replytarget
,
387 longtoduration(time(NULL
)-starttime
, 0));
388 irc_send(":%s 250 %s :Highest connection count: 10 (9 clients)",fromstring
,replytarget
);
392 irc_send(":%s 217 %s P none 0 :0x2000",fromstring
,replytarget
);
397 irc_send(":%s 219 %s %c :End of /STATS report",fromstring
,replytarget
,cargv
[0][0]);