3 #include "../nick/nick.h"
4 #include "../lib/base64.h"
5 #include "../irc/irc.h"
6 #include "../irc/irc_config.h"
7 #include "../core/hooks.h"
8 #include "../core/error.h"
9 #include "../lib/version.h"
10 #include "localuser.h"
19 UserMessageHandler umhandlers
[MAXLOCALUSER
+1];
21 void checklocalkill(int hooknum
, void *nick
);
26 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
30 registerhook(HOOK_IRC_SENDBURSTNICKS
,&sendnickburst
);
31 registerhook(HOOK_NICK_LOSTNICK
,&checklocalkill
);
32 registerserverhandler("P",&handleprivatemsgcmd
,2);
33 registerserverhandler("O",&handleprivatenoticecmd
, 2);
38 * This function creates a local user, and broadcasts it's existence to the net (if connected).
41 nick
*registerlocaluser(char *nickname
, char *ident
, char *host
, char *realname
, char *authname
, flag_t umodes
, UserMessageHandler handler
) {
46 currentlocalunum
=(currentlocalunum
+1)%262142
;
47 while (servernicks
[numerictolong(mynumeric
->content
,2)][currentlocalunum
&MAXLOCALUSER
]!=NULL
) {
48 /* Numeric 262143 on our server is used for "nouser" by the channels module, so cannot be allocated */
49 currentlocalunum
=(currentlocalunum
+1)%262142
;
50 if (++i
>MAXLOCALUSER
) {
55 /* This code is very similar to stuff in nick.c... */
57 newuser
->numeric
=(numerictolong(mynumeric
->content
,2)<<18)|(currentlocalunum
);
58 strncpy(newuser
->nick
,nickname
,NICKLEN
);
59 newuser
->nick
[NICKLEN
]='\0';
60 strncpy(newuser
->ident
,ident
,USERLEN
);
61 newuser
->ident
[USERLEN
]='\0';
62 newuser
->host
=findorcreatehost(host
);
63 newuser
->realname
=findorcreaterealname(realname
);
64 newuser
->nextbyhost
=newuser
->host
->nicks
;
65 newuser
->host
->nicks
=newuser
;
66 newuser
->nextbyrealname
=newuser
->realname
->nicks
;
67 newuser
->realname
->nicks
=newuser
;
68 newuser
->umodes
=umodes
;
69 newuser
->ipaddress
=(127<<24)+(1<<8)+((currentlocalunum%253
)+1); /* Make it look like a valid addr on 127.0.1.0/24 */
70 newuser
->timestamp
=getnettime();
71 newuser
->shident
=NULL
;
72 newuser
->sethost
=NULL
;
74 memset(newuser
->exts
, 0, MAXNICKEXTS
* sizeof(void *));
76 if (IsAccount(newuser
)) {
77 strncpy(newuser
->authname
,authname
,ACCOUNTLEN
);
79 newuser
->authname
[0]='\0';
83 /* Check for nick collision */
84 if ((np
=getnickbynick(nickname
))!=NULL
) {
85 /* Make sure we will win the collision */
86 newuser
->timestamp
=(np
->timestamp
-1);
87 killuser(NULL
, np
, "Nick collision");
93 umhandlers
[(currentlocalunum
&MAXLOCALUSER
)]=handler
;
96 *(gethandlebynumeric(newuser
->numeric
))=newuser
;
97 addnicktohash(newuser
);
98 triggerhook(HOOK_NICK_NEWNICK
,newuser
);
105 * This function changes the name of a given local user
108 int renamelocaluser(nick
*np
, char *newnick
) {
110 time_t timestamp
=getnettime();
115 if (strlen(newnick
) > NICKLEN
)
118 if (homeserver(np
->numeric
)!=mylongnum
)
121 if ((np2
=getnickbynick(newnick
))) {
123 /* Case only name change */
124 strncpy(np
->nick
,newnick
,NICKLEN
);
125 np
->nick
[NICKLEN
]='\0';
126 irc_send("%s N %s %d",longtonumeric(np
->numeric
,5),np
->nick
,np
->timestamp
);
127 triggerhook(HOOK_NICK_RENAME
,np
);
130 /* Kill other user and drop through */
131 timestamp
=np2
->timestamp
-1;
132 killuser(NULL
, np2
, "Nick collision");
136 np
->timestamp
=timestamp
;
137 removenickfromhash(np
);
138 strncpy(np
->nick
,newnick
,NICKLEN
);
139 np
->nick
[NICKLEN
]='\0';
141 irc_send("%s N %s %d",longtonumeric(np
->numeric
,5),np
->nick
,np
->timestamp
);
142 triggerhook(HOOK_NICK_RENAME
,np
);
148 * deregisterlocaluser:
149 * This function removes the given local user from the network
152 int deregisterlocaluser(nick
*np
, char *reason
) {
156 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
157 /* Non-existent user, or user not on this server */
161 if (reason
==NULL
|| *reason
=='\0') {
166 umhandlers
[np
->numeric
&MAXLOCALUSER
]=NULL
;
169 irc_send("%s Q :Quit: %s",longtonumeric(numeric
,5),(defaultreason
?"Leaving":reason
));
176 * hooklocaluserhandler:
177 * This function adds a new handler to the hook chain for a local user
178 * THIS RELIES ON MODULES BEING UNLOADED IN THE CORRECT ORDER.
180 UserMessageHandler
hooklocaluserhandler(nick
*np
, UserMessageHandler newhandler
) {
181 UserMessageHandler oldhandler
= NULL
;
182 if (np
==NULL
|| (homeserver(np
->numeric
)!=mylongnum
)) {
183 /* Non-existent user, or user not on this server */
186 oldhandler
= umhandlers
[np
->numeric
&MAXLOCALUSER
];
187 umhandlers
[np
->numeric
&MAXLOCALUSER
]=newhandler
;
193 * Sends details of a given local nick to the network.
196 void sendnickmsg(nick
*np
) {
199 strncpy(numericbuf
,longtonumeric(np
->numeric
,5),5);
202 irc_send("%s N %s 1 %ld %s %s %s%s%s %s %s :%s",
203 mynumeric
->content
,np
->nick
,np
->timestamp
,np
->ident
,np
->host
->name
->content
,
204 printflags(np
->umodes
,umodeflags
),IsAccount(np
)?" ":"",
205 np
->authname
,longtonumeric(np
->ipaddress
,6),numericbuf
,
206 np
->realname
->name
->content
);
209 void sendnickburst(int hooknum
, void *arg
) {
210 /* Send nick messages for all local users */
214 nh
=servernicks
[numerictolong(mynumeric
->content
,2)];
215 for (i
=0;i
<=MAXLOCALUSER
;i
++) {
222 /* Check for a kill of a local user */
223 void checklocalkill(int hooknum
, void *target
) {
229 numeric
=((nick
*)target
)->numeric
;
231 if (homeserver(numeric
)==mylongnum
) {
232 if (umhandlers
[(numeric
)&MAXLOCALUSER
]!=NULL
) {
233 (umhandlers
[(numeric
)&MAXLOCALUSER
])((nick
*)target
,LU_KILLED
,args
);
238 int handleprivatemsgcmd(void *source
, int cargc
, char **cargv
) {
239 return handlemessageornotice(source
, cargc
, cargv
, 0);
242 int handleprivatenoticecmd(void *source
, int cargc
, char **cargv
) {
243 return handlemessageornotice(source
, cargc
, cargv
, 1);
246 /* Handle privmsg or notice command addressed to user */
247 int handlemessageornotice(void *source
, int cargc
, char **cargv
, int isnotice
) {
251 char targetnick
[NICKLEN
+1];
256 /* Should have target and message */
261 if (cargv
[0][0]=='#' || cargv
[0][0]=='+') {
262 /* Channel message/notice */
266 if ((sender
=getnickbynumericstr((char *)source
))==NULL
) {
267 Error("localuser",ERR_WARNING
,"PRIVMSG from non existant user %s",(char *)source
);
271 /* Check for a "secure" message (foo@bar) */
273 for (i
=0,ch
=cargv
[0];(i
<=NICKLEN
) && (*ch
);i
++,ch
++) {
283 if (!foundat
) { /* Didn't find an @ sign, assume it's a numeric */
284 if ((target
=getnickbynumericstr(cargv
[0]))==NULL
) {
285 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
288 } else { /* Did find @, do a lookup by nick */
289 if ((target
=getnickbynick(targetnick
))==NULL
) {
290 Error("localuser",ERR_DEBUG
,"Couldn't find target for %s",cargv
[0]);
291 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
296 if (homeserver(target
->numeric
)!=mylongnum
) {
297 Error("localuser",ERR_WARNING
,"Got message/notice for someone not on my server");
298 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
302 if (foundat
&& !IsService(target
)) {
303 Error("localuser",ERR_DEBUG
,"Received secure message for %s, but user is not a service",cargv
[0]);
304 irc_send(":%s 401 %s %s :No such nick",myserver
->content
,sender
->nick
,cargv
[0]);
308 if (umhandlers
[(target
->numeric
)&MAXLOCALUSER
]==NULL
) {
309 /* No handler anyhow.. */
313 /* Dispatch the message. */
314 nargs
[0]=(void *)sender
;
315 nargs
[1]=(void *)cargv
[1];
316 (umhandlers
[(target
->numeric
)&MAXLOCALUSER
])(target
,isnotice
?LU_PRIVNOTICE
:(foundat
?LU_SECUREMSG
:LU_PRIVMSG
),nargs
);
321 /* Send message to user */
322 void sendmessagetouser(nick
*source
, nick
*target
, char *format
, ... ) {
327 longtonumeric2(source
->numeric
,5,senderstr
);
330 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
331 /* So max sendable message is 495 bytes. Of course, a client won't be able
332 * to receive this.. */
334 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
337 if (homeserver(target
->numeric
)!=mylongnum
)
338 irc_send("%s P %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
341 /* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
342 void sendsecuremessagetouser(nick
*source
, nick
*target
, char *servername
, char *format
, ... ) {
347 longtonumeric2(source
->numeric
,5,senderstr
);
350 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
351 /* So max sendable message is 495 bytes. Of course, a client won't be able
352 * to receive this.. */
354 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
357 if (homeserver(target
->numeric
)!=mylongnum
)
358 irc_send("%s P %s@%s :%s",senderstr
,target
->nick
,servername
,buf
);
361 /* Send notice to user */
362 void sendnoticetouser(nick
*source
, nick
*target
, char *format
, ... ) {
367 longtonumeric2(source
->numeric
,5,senderstr
);
370 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
371 /* So max sendable message is 495 bytes. Of course, a client won't be able
372 * to receive this.. */
374 vsnprintf(buf
,BUFSIZE
-17,format
,va
);
377 if (homeserver(target
->numeric
)!=mylongnum
)
378 irc_send("%s O %s :%s",senderstr
,longtonumeric(target
->numeric
,5),buf
);
382 void killuser(nick
*source
, nick
*target
, char *format
, ... ) {
385 char sourcestring
[NICKLEN
+USERLEN
+3];
389 /* If we have a null nick, use the server.. */
390 strcpy(senderstr
, mynumeric
->content
);
391 strcpy(sourcestring
, myserver
->content
);
393 strcpy(senderstr
, longtonumeric(source
->numeric
,5));
394 sprintf(sourcestring
,"%s!%s",source
->host
->name
->content
, source
->nick
);
397 va_start(va
, format
);
398 vsnprintf(buf
, BUFSIZE
-17, format
, va
);
401 irc_send("%s D %s :%s (%s)",senderstr
,longtonumeric(target
->numeric
,5),sourcestring
,buf
);
406 void localusersetaccount(nick
*np
, char *accname
) {
408 Error("localuser",ERR_WARNING
,"Tried to set account on user %s already authed", np
->nick
);
413 strncpy(np
->authname
, accname
, ACCOUNTLEN
);
414 np
->authname
[ACCOUNTLEN
]='\0';
417 irc_send("%s AC %s %s %ld",mynumeric
->content
, longtonumeric(np
->numeric
,5), np
->authname
, getnettime());
420 triggerhook(HOOK_NICK_ACCOUNT
, np
);