3 #include "../nick/nick.h"
4 #include "../lib/base64.h"
5 #include "../lib/sstring.h"
6 #include "../irc/irc.h"
7 #include "../irc/irc_config.h"
8 #include "../core/hooks.h"
9 #include "../core/error.h"
10 #include "../lib/version.h"
11 #include "localuser.h"
21 UserMessageHandler umhandlers
[MAXLOCALUSER
+1];
23 typedef struct pendingkill
{
24 nick
*source
, *target
;
26 struct pendingkill
*next
;
29 pendingkill
*pendingkilllist
;
31 void checklocalkill(int hooknum
, void *nick
);
32 void clearpendingkills(int hooknum
, void *arg
);
33 void checkpendingkills(int hooknum
, void *arg
);
34 void _killuser(nick
*source
, nick
*target
, char *reason
);
39 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
44 registerhook(HOOK_IRC_SENDBURSTNICKS
,&sendnickburst
);
45 registerhook(HOOK_NICK_KILL
,&checklocalkill
);
46 registerhook(HOOK_NICK_LOSTNICK
,&checkpendingkills
); /* CHECK ME -> should this hook KILL or LOSTNICK or BOTH */
47 registerhook(HOOK_CORE_ENDOFHOOKSQUEUE
,&clearpendingkills
);
48 registerserverhandler("P",&handleprivatemsgcmd
,2);
49 registerserverhandler("O",&handleprivatenoticecmd
, 2);
55 for (pk
=pendingkilllist
;pk
;pk
=pendingkilllist
) {
56 pendingkilllist
= pk
->next
;
57 freesstring(pk
->reason
);
61 deregisterhook(HOOK_IRC_SENDBURSTNICKS
,&sendnickburst
);
62 deregisterhook(HOOK_NICK_KILL
,&checklocalkill
);
63 deregisterhook(HOOK_NICK_LOSTNICK
,&checkpendingkills
); /* CHECK ME -> should this hook KILL or LOSTNICK or BOTH */
64 deregisterhook(HOOK_CORE_ENDOFHOOKSQUEUE
,&clearpendingkills
);
66 deregisterserverhandler("P",&handleprivatemsgcmd
);
67 deregisterserverhandler("O",&handleprivatenoticecmd
);
71 * registerlocaluserflagsip:
72 * This function creates a local user, and broadcasts it's existence to the net (if connected).
75 nick
*registerlocaluserflagsip(char *nickname
, char *ident
, char *host
, char *realname
, char *authname
, unsigned long authid
, flag_t accountflags
, flag_t umodes
, struct irc_in_addr
*ipaddress
, UserMessageHandler handler
) {
78 struct irc_in_addr tmpipaddress
;
81 currentlocalunum
=(currentlocalunum
+1)%262142
;
82 while (servernicks
[numerictolong(mynumeric
->content
,2)][currentlocalunum
&MAXLOCALUSER
]!=NULL
) {
83 /* Numeric 262143 on our server is used for "nouser" by the channels module, so cannot be allocated */
84 currentlocalunum
=(currentlocalunum
+1)%262142
;
85 if (++i
>MAXLOCALUSER
) {
90 /* This code is very similar to stuff in nick.c... */
92 newuser
->numeric
=(numerictolong(mynumeric
->content
,2)<<18)|(currentlocalunum
);
93 strncpy(newuser
->nick
,nickname
,NICKLEN
);
94 newuser
->nick
[NICKLEN
]='\0';
95 strncpy(newuser
->ident
,ident
,USERLEN
);
96 newuser
->ident
[USERLEN
]='\0';
97 newuser
->host
=findorcreatehost(host
);
98 newuser
->realname
=findorcreaterealname(realname
);
99 newuser
->nextbyhost
=newuser
->host
->nicks
;
100 newuser
->host
->nicks
=newuser
;
101 newuser
->nextbyrealname
=newuser
->realname
->nicks
;
102 newuser
->realname
->nicks
=newuser
;
103 newuser
->umodes
=umodes
;
106 ipaddress
= &tmpipaddress
;
108 memset(ipaddress
, 0, sizeof(struct irc_in_addr
));
109 ((unsigned short *)(ipaddress
->in6_16
))[5] = 65535;
110 ((unsigned short *)(ipaddress
->in6_16
))[6] = 127;
111 ((unsigned char *)(ipaddress
->in6_16
))[14] = 1;
112 ((unsigned char *)(ipaddress
->in6_16
))[15] = (currentlocalunum%253
)+1;
115 memcpy(&newuser
->ipaddress
, ipaddress
, sizeof(struct irc_in_addr
));
117 newuser
->ipnode
= refnode(iptree
, ipaddress
, PATRICIA_MAXBITS
);
118 node_increment_usercount(newuser
->ipnode
);
120 newuser
->timestamp
=getnettime();
121 newuser
->shident
=NULL
;
122 newuser
->sethost
=NULL
;
125 memset(newuser
->exts
, 0, MAXNICKEXTS
* sizeof(void *));
127 if (IsOper(newuser
)) {
128 newuser
->opername
= getsstring("-", ACCOUNTLEN
);
130 newuser
->opername
= NULL
;
133 newuser
->accountts
=0;
135 newuser
->authname
=NULLAUTHNAME
;
136 if (IsAccount(newuser
)) {
137 newuser
->accountts
=newuser
->timestamp
;
139 newuser
->auth
=findorcreateauthname(authid
, authname
);
140 newuser
->authname
=newuser
->auth
->name
;
141 newuser
->auth
->usercount
++;
142 newuser
->nextbyauthname
=newuser
->auth
->nicks
;
143 newuser
->auth
->nicks
=newuser
;
144 newuser
->auth
->flags
=accountflags
;
147 this is done for three reasons:
148 1: so I don't have to change 500 pieces of code
149 2: so services can be authed with special reserved ids
150 3: saves space over the old authname per user method
152 newuser
->authname
=malloc(strlen(authname
) + 1);
153 strcpy(newuser
->authname
,authname
);
157 newuser
->cloak_count
= 0;
158 newuser
->cloak_extra
= NULL
;
159 newuser
->message
= NULL
;
162 /* Check for nick collision */
163 if ((np
=getnickbynick(nickname
))!=NULL
) {
164 /* Make sure we will win the collision */
165 newuser
->timestamp
=(np
->timestamp
-1);
166 killuser(NULL
, np
, "Nick collision");
168 sendnickmsg(newuser
);
172 umhandlers
[(currentlocalunum
&MAXLOCALUSER
)]=handler
;
175 *(gethandlebynumeric(newuser
->numeric
))=newuser
;
176 addnicktohash(newuser
);
177 triggerhook(HOOK_NICK_NEWNICK
,newuser
);
184 * This function changes the name of a given local user
187 int renamelocaluser(nick
*np
, char *newnick
) {
190 time_t timestamp
=getnettime();
192 char oldnick
[NICKLEN
+1];
197 if (strlen(newnick
) > NICKLEN
)
200 if (homeserver(np
->numeric
)!=mylongnum
)
203 strncpy(oldnick
,np
->nick
,NICKLEN
);
204 oldnick
[NICKLEN
]='\0';
206 harg
[1]=(void *)oldnick
;
208 if ((np2
=getnickbynick(newnick
))) {
210 /* Case only name change */
211 strncpy(np
->nick
,newnick
,NICKLEN
);
212 np
->nick
[NICKLEN
]='\0';
213 irc_send("%s N %s %jd",iptobase64(ipbuf
, &(np
->ipaddress
), sizeof(ipbuf
), 1),np
->nick
,(intmax_t)np
->timestamp
);
214 triggerhook(HOOK_NICK_RENAME
,harg
);
217 /* Kill other user and drop through */
218 timestamp
=np2
->timestamp
-1;
219 killuser(NULL
, np2
, "Nick collision");
223 np
->timestamp
=timestamp
;
224 removenickfromhash(np
);
225 strncpy(np
->nick
,newnick
,NICKLEN
);
226 np
->nick
[NICKLEN
]='\0';
228 irc_send("%s N %s %jd",longtonumeric(np
->numeric
,5),np
->nick
,(intmax_t)np
->timestamp
);
229 triggerhook(HOOK_NICK_RENAME
,harg
);
235 * deregisterlocaluser:
236 * This function removes the given local user from the network
239 int deregisterlocaluser(nick
*np
, char *reason
) {
244 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
245 /* Non-existent user, or user not on this server */
249 if (reason
==NULL
|| *reason
=='\0') {
250 sprintf(reasonstr
,"Quit");
252 snprintf(reasonstr
,510,"Quit: %s",reason
);
258 triggerhook(HOOK_NICK_QUIT
, harg
);
261 umhandlers
[np
->numeric
&MAXLOCALUSER
]=NULL
;
264 irc_send("%s Q :%s",longtonumeric(numeric
,5),reasonstr
);
271 * hooklocaluserhandler:
272 * This function adds a new handler to the hook chain for a local user
273 * THIS RELIES ON MODULES BEING UNLOADED IN THE CORRECT ORDER.
275 UserMessageHandler
hooklocaluserhandler(nick
*np
, UserMessageHandler newhandler
) {
276 UserMessageHandler oldhandler
= NULL
;
277 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
278 /* Non-existent user, or user not on this server */
281 oldhandler
= umhandlers
[np
->numeric
&MAXLOCALUSER
];
282 umhandlers
[np
->numeric
&MAXLOCALUSER
]=newhandler
;
288 * Sends details of a given local nick to the network.
291 void sendnickmsg(nick
*np
) {
293 char ipbuf
[25], operbuf
[ACCOUNTLEN
+ 5];
294 char accountbuf
[100];
296 strncpy(numericbuf
,longtonumeric(np
->numeric
,5),5);
299 if(IsOper(np
) && (serverlist
[myhub
].flags
& SMODE_OPERNAME
)) {
300 snprintf(operbuf
,sizeof(operbuf
)," %s",np
->opername
?np
->opername
->content
:"-");
308 if(np
->auth
->flags
) {
309 snprintf(accountbuf
,sizeof(accountbuf
)," %s:%ld:%lu:%"PRIu64
,np
->authname
,np
->accountts
,np
->auth
->userid
,np
->auth
->flags
);
311 snprintf(accountbuf
,sizeof(accountbuf
)," %s:%ld:%lu",np
->authname
,np
->accountts
,np
->auth
->userid
);
313 } else if(np
->authname
) {
314 snprintf(accountbuf
,sizeof(accountbuf
)," %s:%ld:0",np
->authname
,np
->accountts
);
318 irc_send("%s N %s 1 %ld %s %s %s%s%s %s %s :%s",
319 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
320 printflags(np
->umodes
,umodeflags
),operbuf
,accountbuf
,iptobase64(ipbuf
,&(np
->ipaddress
),
321 sizeof(ipbuf
),1),numericbuf
,np
->realname
->name
->content
);
324 void sendnickburst(int hooknum
, void *arg
) {
325 /* Send nick messages for all local users */
329 nh
=servernicks
[numerictolong(mynumeric
->content
,2)];
330 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
337 /* Check for a kill of a local user */
338 void checklocalkill(int hooknum
, void *arg
) {
340 nick
*target
=args
[0];
341 char *reason
=args
[1];
348 numeric
=((nick
*)target
)->numeric
;
350 if (homeserver(numeric
)==mylongnum
) {
351 if (umhandlers
[(numeric
)&MAXLOCALUSER
]!=NULL
) {
352 (umhandlers
[(numeric
)&MAXLOCALUSER
])((nick
*)target
,LU_KILLED
,myargs
);
357 int handleprivatemsgcmd(void *source
, int cargc
, char **cargv
) {
358 return handlemessageornotice(source
, cargc
, cargv
, 0);
361 int handleprivatenoticecmd(void *source
, int cargc
, char **cargv
) {
362 return handlemessageornotice(source
, cargc
, cargv
, 1);
365 /* Handle privmsg or notice command addressed to user */
366 int handlemessageornotice(void *source
, int cargc
, char **cargv
, int isnotice
) {
370 char targetnick
[NICKLEN
+1];
375 /* Should have target and message */
380 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
381 Error("localuser",ERR_WARNING
,"PRIVMSG from non existant user %s",(char *)source
);
385 freesstring(sender
->message
);
386 sender
->message
= getsstring(cargv
[1], 512);
390 nargs
[2] = (void *)(uintptr_t)isnotice
;
391 triggerhook(HOOK_NICK_MESSAGE
, nargs
);
393 if (cargv
[0][0]=='#' || cargv
[0][0]=='+') {
394 /* Channel message/notice */
398 /* Check for a "secure" message (foo@bar) */
400 for (i
=0,ch
=cargv
[0];(i
<=NICKLEN
) && (*ch
);i
++,ch
++) {
410 if (!foundat
) { /* Didn't find an @ sign, assume it's a numeric */
411 if ((target
=getnickbynumericstr(cargv
[0]))==NULL
) {
412 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
415 } else { /* Did find @, do a lookup by nick */
416 if ((target
=getnickbynick(targetnick
))==NULL
) {
417 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
418 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
423 if (homeserver(target
->numeric
)!=mylongnum
) {
424 Error("localuser",ERR_WARNING
,"Got message/notice for someone not on my server");
425 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
429 if (foundat
&& !IsService(target
)) {
430 Error("localuser",ERR_DEBUG
,"Received secure message for %s, but user is not a service",cargv
[0]);
431 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
435 if (umhandlers
[(target
->numeric
)&MAXLOCALUSER
]==NULL
) {
436 /* No handler anyhow.. */
440 /* Dispatch the message. */
441 nargs
[0]=(void *)sender
;
442 nargs
[1]=(void *)cargv
[1];
443 (umhandlers
[(target
->numeric
)&MAXLOCALUSER
])(target
,isnotice
?LU_PRIVNOTICE
:(foundat
?LU_SECUREMSG
:LU_PRIVMSG
),nargs
);
448 /* Send message to user */
449 void sendmessagetouser(nick
*source
, nick
*target
, char *format
, ... ) {
454 longtonumeric2(source
->numeric
,5,senderstr
);
457 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
458 /* So max sendable message is 495 bytes. Of course, a client won't be able
459 * to receive this.. */
461 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
464 if (homeserver(target
->numeric
)!=mylongnum
)
465 irc_send("%s P %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
468 /* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
469 void sendsecuremessagetouser(nick
*source
, nick
*target
, char *servername
, char *format
, ... ) {
474 longtonumeric2(source
->numeric
,5,senderstr
);
477 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
478 /* So max sendable message is 495 bytes. Of course, a client won't be able
479 * to receive this.. */
481 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
484 if (homeserver(target
->numeric
)!=mylongnum
)
485 irc_send("%s P %s@%s :%s",senderstr
,target
->nick
,servername
,buf
);
488 /* Send notice to user */
489 void sendnoticetouser(nick
*source
, nick
*target
, char *format
, ... ) {
494 longtonumeric2(source
->numeric
,5,senderstr
);
497 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
498 /* So max sendable message is 495 bytes. Of course, a client won't be able
499 * to receive this.. */
501 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
504 if (homeserver(target
->numeric
)!=mylongnum
)
505 irc_send("%s O %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
509 void killuser(nick
*source
, nick
*target
, char *format
, ... ) {
514 va_start(va
, format
);
515 vsnprintf(buf
, BUFSIZE
-17, format
, va
);
518 if (hookqueuelength
) {
519 for (pk
= pendingkilllist
; pk
; pk
= pk
->next
)
520 if (pk
->target
== target
)
523 Error("localuser", ERR_DEBUG
, "Adding pending kill for %s", target
->nick
);
524 pk
= (pendingkill
*)malloc(sizeof(pendingkill
));
527 pk
->reason
= getsstring(buf
, BUFSIZE
);
528 pk
->next
= pendingkilllist
;
529 pendingkilllist
= pk
;
531 _killuser(source
, target
, buf
);
535 void sethostuser(nick
*target
, char *ident
, char *host
) {
536 irc_send("%s SH %s %s %s", mynumeric
->content
, longtonumeric(target
->numeric
, 5), ident
, host
);
539 void _killuser(nick
*source
, nick
*target
, char *reason
) {
541 char sourcestring
[HOSTLEN
+NICKLEN
+3];
546 /* If we have a null nick, use the server.. */
547 strcpy(senderstr
, mynumeric
->content
);
548 strcpy(sourcestring
, myserver
->content
);
550 strcpy(senderstr
, longtonumeric(source
->numeric
,5));
551 sprintf(sourcestring
,"%s!%s",source
->host
->name
->content
, source
->nick
);
554 snprintf(reasonstr
,512,"%s (%s)",sourcestring
,reason
);
557 irc_send("%s D %s :%s",senderstr
,longtonumeric(target
->numeric
,5),reasonstr
);
561 triggerhook(HOOK_NICK_KILL
, args
);
566 void clearpendingkills(int hooknum
, void *arg
) {
569 pk
= pendingkilllist
;
571 pendingkilllist
= pk
->next
;
574 Error("localuser", ERR_DEBUG
, "Processing pending kill for %s", pk
->target
->nick
);
575 _killuser(pk
->source
, pk
->target
, pk
->reason
->content
);
578 freesstring(pk
->reason
);
580 pk
= pendingkilllist
;
584 void checkpendingkills(int hooknum
, void *arg
) {
585 nick
*np
= (nick
*)arg
;
588 for (pk
=pendingkilllist
; pk
; pk
= pk
->next
) {
589 if (pk
->source
== np
) {
590 Error("localuser", ERR_INFO
, "Pending kill source %s got deleted, NULL'ing source for pending kill", np
->nick
);
593 if (pk
->target
== np
) {
594 Error("localuser", ERR_INFO
, "Pending kill target %s got deleted, NULL'ing target for pending kill", np
->nick
);
600 void sendaccountmessage(nick
*np
) {
601 if (connected
&& IsAccount(np
)) {
603 if (np
->auth
->flags
) {
604 irc_send("%s AC %s %s %ld %lu %"PRIu64
,mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
, np
->auth
->userid
, np
->auth
->flags
);
606 irc_send("%s AC %s %s %ld %lu",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
, np
->auth
->userid
);
609 irc_send("%s AC %s %s %ld 0",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
);
614 /* Auth user, don't use to set flags after authing */
615 void localusersetaccount(nick
*np
, char *accname
, unsigned long accid
, u_int64_t accountflags
, time_t authTS
) {
617 Error("localuser",ERR_WARNING
,"Tried to set account on user %s already authed", np
->nick
);
622 np
->accountts
=authTS
?authTS
:getnettime();
625 np
->auth
=findorcreateauthname(accid
, accname
);
626 np
->auth
->usercount
++;
627 np
->authname
=np
->auth
->name
;
628 np
->nextbyauthname
=np
->auth
->nicks
;
630 np
->auth
->flags
=accountflags
;
633 np
->authname
=malloc(strlen(accname
) + 1);
634 strcpy(np
->authname
,accname
);
637 sendaccountmessage(np
);
639 triggerhook(HOOK_NICK_ACCOUNT
, np
);
642 void localusersetumodes(nick
*np
, flag_t newmodes
) {
644 irc_send("%s M %s %s", longtonumeric(np
->numeric
,5), np
->nick
, printflagdiff(np
->umodes
, newmodes
, umodeflags
));
647 np
->umodes
= newmodes
;
650 void localusersetaccountflags(authname
*anp
, u_int64_t accountflags
) {
653 u_int64_t oldflags
= anp
->flags
;
657 anp
->flags
= accountflags
;
659 for(np
=anp
->nicks
;np
;np
=np
->nextbyauthname
)
660 sendaccountmessage(np
);
662 triggerhook(HOOK_AUTH_FLAGSUPDATED
, arg
);
665 void localuseraddcloaktarget(nick
*np
, nick
*target
) {
666 char snumeric
[10], tnumeric
[10];
668 strcpy(snumeric
, longtonumeric(np
->numeric
,5));
669 strcpy(tnumeric
, longtonumeric(target
->numeric
,5));
671 irc_send("%s CA %s", snumeric
, tnumeric
);
673 addcloaktarget(np
, target
);
676 void localuserclearcloaktargets(nick
*np
) {
677 irc_send("%s CU", longtonumeric(np
->numeric
,5));
678 clearcloaktargets(np
);