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"
20 UserMessageHandler umhandlers
[MAXLOCALUSER
+1];
22 typedef struct pendingkill
{
23 nick
*source
, *target
;
25 struct pendingkill
*next
;
28 pendingkill
*pendingkilllist
;
30 void checklocalkill(int hooknum
, void *nick
);
31 void clearpendingkills(int hooknum
, void *arg
);
32 void checkpendingkills(int hooknum
, void *arg
);
33 void _killuser(nick
*source
, nick
*target
, char *reason
);
38 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
43 registerhook(HOOK_IRC_SENDBURSTNICKS
,&sendnickburst
);
44 registerhook(HOOK_NICK_KILL
,&checklocalkill
);
45 registerhook(HOOK_NICK_LOSTNICK
,&checkpendingkills
); /* CHECK ME -> should this hook KILL or LOSTNICK or BOTH */
46 registerhook(HOOK_CORE_ENDOFHOOKSQUEUE
,&clearpendingkills
);
47 registerserverhandler("P",&handleprivatemsgcmd
,2);
48 registerserverhandler("O",&handleprivatenoticecmd
, 2);
54 for (pk
=pendingkilllist
;pk
;pk
=pendingkilllist
) {
55 pendingkilllist
= pk
->next
;
56 freesstring(pk
->reason
);
60 deregisterhook(HOOK_IRC_SENDBURSTNICKS
,&sendnickburst
);
61 deregisterhook(HOOK_NICK_KILL
,&checklocalkill
);
62 deregisterhook(HOOK_NICK_LOSTNICK
,&checkpendingkills
); /* CHECK ME -> should this hook KILL or LOSTNICK or BOTH */
63 deregisterhook(HOOK_CORE_ENDOFHOOKSQUEUE
,&clearpendingkills
);
65 deregisterserverhandler("P",&handleprivatemsgcmd
);
66 deregisterserverhandler("O",&handleprivatenoticecmd
);
70 * registerlocaluserwithuseridflags:
71 * This function creates a local user, and broadcasts it's existence to the net (if connected).
74 nick
*registerlocaluserwithuseridflags(char *nickname
, char *ident
, char *host
, char *realname
, char *authname
, unsigned long authid
, flag_t umodes
, flag_t accountflags
, UserMessageHandler handler
) {
77 struct irc_in_addr ipaddress
;
80 currentlocalunum
=(currentlocalunum
+1)%262142
;
81 while (servernicks
[numerictolong(mynumeric
->content
,2)][currentlocalunum
&MAXLOCALUSER
]!=NULL
) {
82 /* Numeric 262143 on our server is used for "nouser" by the channels module, so cannot be allocated */
83 currentlocalunum
=(currentlocalunum
+1)%262142
;
84 if (++i
>MAXLOCALUSER
) {
89 /* This code is very similar to stuff in nick.c... */
91 newuser
->numeric
=(numerictolong(mynumeric
->content
,2)<<18)|(currentlocalunum
);
92 strncpy(newuser
->nick
,nickname
,NICKLEN
);
93 newuser
->nick
[NICKLEN
]='\0';
94 strncpy(newuser
->ident
,ident
,USERLEN
);
95 newuser
->ident
[USERLEN
]='\0';
96 newuser
->host
=findorcreatehost(host
);
97 newuser
->realname
=findorcreaterealname(realname
);
98 newuser
->nextbyhost
=newuser
->host
->nicks
;
99 newuser
->host
->nicks
=newuser
;
100 newuser
->nextbyrealname
=newuser
->realname
->nicks
;
101 newuser
->realname
->nicks
=newuser
;
102 newuser
->umodes
=umodes
;
103 newuser
->accountflags
=accountflags
;
105 memset(&ipaddress
, 0, sizeof(ipaddress
));
106 ((unsigned short *)(ipaddress
.in6_16
))[5] = 65535;
107 ((unsigned short *)(ipaddress
.in6_16
))[6] = 127;
108 ((unsigned char *)(ipaddress
.in6_16
))[14] = 1;
109 ((unsigned char *)(ipaddress
.in6_16
))[15] = (currentlocalunum%253
)+1;
111 newuser
->ipnode
= refnode(iptree
, &ipaddress
, PATRICIA_MAXBITS
);
112 node_increment_usercount(newuser
->ipnode
);
114 newuser
->timestamp
=getnettime();
115 newuser
->shident
=NULL
;
116 newuser
->sethost
=NULL
;
118 memset(newuser
->exts
, 0, MAXNICKEXTS
* sizeof(void *));
120 if (IsAccount(newuser
)) {
121 strncpy(newuser
->authname
,authname
,ACCOUNTLEN
);
122 newuser
->accountts
=newuser
->timestamp
;
124 newuser
->auth
=findorcreateauthname(authid
);
125 newuser
->auth
->usercount
++;
126 newuser
->nextbyauthname
=newuser
->auth
->nicks
;
127 newuser
->auth
->nicks
=newuser
;
132 newuser
->authname
[0]='\0';
133 newuser
->accountts
=0;
138 /* Check for nick collision */
139 if ((np
=getnickbynick(nickname
))!=NULL
) {
140 /* Make sure we will win the collision */
141 newuser
->timestamp
=(np
->timestamp
-1);
142 killuser(NULL
, np
, "Nick collision");
144 sendnickmsg(newuser
);
148 umhandlers
[(currentlocalunum
&MAXLOCALUSER
)]=handler
;
151 *(gethandlebynumeric(newuser
->numeric
))=newuser
;
152 addnicktohash(newuser
);
153 triggerhook(HOOK_NICK_NEWNICK
,newuser
);
160 * This function changes the name of a given local user
163 int renamelocaluser(nick
*np
, char *newnick
) {
166 time_t timestamp
=getnettime();
171 if (strlen(newnick
) > NICKLEN
)
174 if (homeserver(np
->numeric
)!=mylongnum
)
177 if ((np2
=getnickbynick(newnick
))) {
179 /* Case only name change */
180 strncpy(np
->nick
,newnick
,NICKLEN
);
181 np
->nick
[NICKLEN
]='\0';
182 irc_send("%s N %s %d",iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),np
->nick
,np
->timestamp
);
183 triggerhook(HOOK_NICK_RENAME
,np
);
186 /* Kill other user and drop through */
187 timestamp
=np2
->timestamp
-1;
188 killuser(NULL
, np2
, "Nick collision");
192 np
->timestamp
=timestamp
;
193 removenickfromhash(np
);
194 strncpy(np
->nick
,newnick
,NICKLEN
);
195 np
->nick
[NICKLEN
]='\0';
197 irc_send("%s N %s %d",longtonumeric(np
->numeric
,5),np
->nick
,np
->timestamp
);
198 triggerhook(HOOK_NICK_RENAME
,np
);
204 * deregisterlocaluser:
205 * This function removes the given local user from the network
208 int deregisterlocaluser(nick
*np
, char *reason
) {
213 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
214 /* Non-existent user, or user not on this server */
218 if (reason
==NULL
|| *reason
=='\0') {
219 sprintf(reasonstr
,"Quit");
221 snprintf(reasonstr
,510,"Quit: %s",reason
);
227 triggerhook(HOOK_NICK_QUIT
, harg
);
230 umhandlers
[np
->numeric
&MAXLOCALUSER
]=NULL
;
233 irc_send("%s Q :%s",longtonumeric(numeric
,5),reasonstr
);
240 * hooklocaluserhandler:
241 * This function adds a new handler to the hook chain for a local user
242 * THIS RELIES ON MODULES BEING UNLOADED IN THE CORRECT ORDER.
244 UserMessageHandler
hooklocaluserhandler(nick
*np
, UserMessageHandler newhandler
) {
245 UserMessageHandler oldhandler
= NULL
;
246 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
247 /* Non-existent user, or user not on this server */
250 oldhandler
= umhandlers
[np
->numeric
&MAXLOCALUSER
];
251 umhandlers
[np
->numeric
&MAXLOCALUSER
]=newhandler
;
257 * Sends details of a given local nick to the network.
260 void sendnickmsg(nick
*np
) {
264 strncpy(numericbuf
,longtonumeric(np
->numeric
,5),5);
268 if(np
->accountflags
) {
269 irc_send("%s N %s 1 %ld %s %s %s %s:%ld:%lu:" FLAG_T_SPECIFIER
" %s %s :%s",
270 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
271 printflags(np
->umodes
,umodeflags
),np
->authname
,np
->accountts
,np
->auth
?np
->auth
->userid
:0,np
->accountflags
,
272 iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),numericbuf
,np
->realname
->name
->content
);
273 } else if (np
->auth
) {
274 irc_send("%s N %s 1 %ld %s %s %s %s:%ld:%lu %s %s :%s",
275 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
276 printflags(np
->umodes
,umodeflags
),np
->authname
,np
->accountts
,np
->auth
->userid
,
277 iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),numericbuf
,np
->realname
->name
->content
);
278 } else if (np
->accountts
) {
279 irc_send("%s N %s 1 %ld %s %s %s %s:%ld %s %s :%s",
280 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
281 printflags(np
->umodes
,umodeflags
),np
->authname
,np
->accountts
,
282 iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),numericbuf
,np
->realname
->name
->content
);
284 irc_send("%s N %s 1 %ld %s %s %s %s %s %s :%s",
285 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
286 printflags(np
->umodes
,umodeflags
),np
->authname
,
287 iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),numericbuf
,np
->realname
->name
->content
);
290 irc_send("%s N %s 1 %ld %s %s %s %s %s :%s",
291 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
292 printflags(np
->umodes
,umodeflags
),iptobase64(ipbuf
, &(np
->p_ipaddr
), sizeof(ipbuf
), 1),
293 numericbuf
,np
->realname
->name
->content
);
297 void sendnickburst(int hooknum
, void *arg
) {
298 /* Send nick messages for all local users */
302 nh
=servernicks
[numerictolong(mynumeric
->content
,2)];
303 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
310 /* Check for a kill of a local user */
311 void checklocalkill(int hooknum
, void *arg
) {
313 nick
*target
=args
[0];
314 char *reason
=args
[1];
321 numeric
=((nick
*)target
)->numeric
;
323 if (homeserver(numeric
)==mylongnum
) {
324 if (umhandlers
[(numeric
)&MAXLOCALUSER
]!=NULL
) {
325 (umhandlers
[(numeric
)&MAXLOCALUSER
])((nick
*)target
,LU_KILLED
,myargs
);
330 int handleprivatemsgcmd(void *source
, int cargc
, char **cargv
) {
331 return handlemessageornotice(source
, cargc
, cargv
, 0);
334 int handleprivatenoticecmd(void *source
, int cargc
, char **cargv
) {
335 return handlemessageornotice(source
, cargc
, cargv
, 1);
338 /* Handle privmsg or notice command addressed to user */
339 int handlemessageornotice(void *source
, int cargc
, char **cargv
, int isnotice
) {
343 char targetnick
[NICKLEN
+1];
348 /* Should have target and message */
353 if (cargv
[0][0]=='#' || cargv
[0][0]=='+') {
354 /* Channel message/notice */
358 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
359 Error("localuser",ERR_WARNING
,"PRIVMSG from non existant user %s",(char *)source
);
363 /* Check for a "secure" message (foo@bar) */
365 for (i
=0,ch
=cargv
[0];(i
<=NICKLEN
) && (*ch
);i
++,ch
++) {
375 if (!foundat
) { /* Didn't find an @ sign, assume it's a numeric */
376 if ((target
=getnickbynumericstr(cargv
[0]))==NULL
) {
377 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
380 } else { /* Did find @, do a lookup by nick */
381 if ((target
=getnickbynick(targetnick
))==NULL
) {
382 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
383 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
388 if (homeserver(target
->numeric
)!=mylongnum
) {
389 Error("localuser",ERR_WARNING
,"Got message/notice for someone not on my server");
390 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
394 if (foundat
&& !IsService(target
)) {
395 Error("localuser",ERR_DEBUG
,"Received secure message for %s, but user is not a service",cargv
[0]);
396 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
400 if (umhandlers
[(target
->numeric
)&MAXLOCALUSER
]==NULL
) {
401 /* No handler anyhow.. */
405 /* Dispatch the message. */
406 nargs
[0]=(void *)sender
;
407 nargs
[1]=(void *)cargv
[1];
408 (umhandlers
[(target
->numeric
)&MAXLOCALUSER
])(target
,isnotice
?LU_PRIVNOTICE
:(foundat
?LU_SECUREMSG
:LU_PRIVMSG
),nargs
);
413 /* Send message to user */
414 void sendmessagetouser(nick
*source
, nick
*target
, char *format
, ... ) {
419 longtonumeric2(source
->numeric
,5,senderstr
);
422 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
423 /* So max sendable message is 495 bytes. Of course, a client won't be able
424 * to receive this.. */
426 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
429 if (homeserver(target
->numeric
)!=mylongnum
)
430 irc_send("%s P %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
433 /* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
434 void sendsecuremessagetouser(nick
*source
, nick
*target
, char *servername
, char *format
, ... ) {
439 longtonumeric2(source
->numeric
,5,senderstr
);
442 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
443 /* So max sendable message is 495 bytes. Of course, a client won't be able
444 * to receive this.. */
446 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
449 if (homeserver(target
->numeric
)!=mylongnum
)
450 irc_send("%s P %s@%s :%s",senderstr
,target
->nick
,servername
,buf
);
453 /* Send notice to user */
454 void sendnoticetouser(nick
*source
, nick
*target
, char *format
, ... ) {
459 longtonumeric2(source
->numeric
,5,senderstr
);
462 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
463 /* So max sendable message is 495 bytes. Of course, a client won't be able
464 * to receive this.. */
466 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
469 if (homeserver(target
->numeric
)!=mylongnum
)
470 irc_send("%s O %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
474 void killuser(nick
*source
, nick
*target
, char *format
, ... ) {
479 va_start(va
, format
);
480 vsnprintf(buf
, BUFSIZE
-17, format
, va
);
483 if (hookqueuelength
) {
484 for (pk
= pendingkilllist
; pk
; pk
= pk
->next
)
485 if (pk
->target
== target
)
488 Error("localuser", ERR_DEBUG
, "Adding pending kill for %s", target
->nick
);
489 pk
= (pendingkill
*)malloc(sizeof(pendingkill
));
492 pk
->reason
= getsstring(buf
, BUFSIZE
);
493 pk
->next
= pendingkilllist
;
494 pendingkilllist
= pk
;
496 _killuser(source
, target
, buf
);
500 void sethostuser(nick
*target
, char *ident
, char *host
) {
501 irc_send("%s SH %s %s %s", mynumeric
->content
, longtonumeric(target
->numeric
, 5), ident
, host
);
504 void _killuser(nick
*source
, nick
*target
, char *reason
) {
506 char sourcestring
[HOSTLEN
+NICKLEN
+3];
509 /* If we have a null nick, use the server.. */
510 strcpy(senderstr
, mynumeric
->content
);
511 strcpy(sourcestring
, myserver
->content
);
513 strcpy(senderstr
, longtonumeric(source
->numeric
,5));
514 sprintf(sourcestring
,"%s!%s",source
->host
->name
->content
, source
->nick
);
517 irc_send("%s D %s :%s (%s)",senderstr
,longtonumeric(target
->numeric
,5),sourcestring
,reason
);
521 void clearpendingkills(int hooknum
, void *arg
) {
524 pk
= pendingkilllist
;
526 pendingkilllist
= pk
->next
;
529 Error("localuser", ERR_DEBUG
, "Processing pending kill for %s", pk
->target
->nick
);
530 _killuser(pk
->source
, pk
->target
, pk
->reason
->content
);
533 freesstring(pk
->reason
);
535 pk
= pendingkilllist
;
539 void checkpendingkills(int hooknum
, void *arg
) {
540 nick
*np
= (nick
*)arg
;
543 for (pk
=pendingkilllist
; pk
; pk
= pk
->next
) {
544 if (pk
->source
== np
) {
545 Error("localuser", ERR_INFO
, "Pending kill source %s got deleted, NULL'ing source for pending kill", np
->nick
);
548 if (pk
->target
== np
) {
549 Error("localuser", ERR_INFO
, "Pending kill target %s got deleted, NULL'ing target for pending kill", np
->nick
);
556 void localusersetaccountwithuseridflagsts(nick
*np
, char *accname
, unsigned long accid
, flag_t accountflags
, time_t authTS
) {
558 Error("localuser",ERR_WARNING
,"Tried to set account on user %s already authed", np
->nick
);
563 strncpy(np
->authname
, accname
, ACCOUNTLEN
);
564 np
->authname
[ACCOUNTLEN
]='\0';
565 np
->accountts
=authTS
?authTS
:getnettime();
566 np
->accountflags
=accountflags
;
569 np
->auth
=findorcreateauthname(accid
);
570 np
->auth
->usercount
++;
571 np
->nextbyauthname
=np
->auth
->nicks
;
578 if (np
->accountflags
) {
579 irc_send("%s AC %s %s %ld %lu %lu",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
, np
->auth
?np
->auth
->userid
:0, np
->accountflags
);
580 } else if (np
->auth
) {
581 irc_send("%s AC %s %s %ld %lu",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
, np
->auth
->userid
);
583 irc_send("%s AC %s %s %ld",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, np
->accountts
);
587 triggerhook(HOOK_NICK_ACCOUNT
, np
);
590 void localusersetumodes(nick
*np
, flag_t newmodes
) {
592 irc_send("%s M %s %s", longtonumeric(np
->numeric
,5), np
->nick
, printflagdiff(np
->umodes
, newmodes
, umodeflags
));
595 np
->umodes
= newmodes
;