]> jfr.im git - irc/quakenet/newserv.git/blame - localuser/localuser.c
r645@blue (orig r493): slug | 2006-05-15 23:31:10 +0100
[irc/quakenet/newserv.git] / localuser / localuser.c
CommitLineData
c86edd1d
Q
1/* localuser.c */
2
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 "localuser.h"
10
11#include <string.h>
12#include <stdarg.h>
13#include <stdio.h>
14
15int currentlocalunum;
16UserMessageHandler umhandlers[MAXLOCALUSER+1];
17
18void checklocalkill(int hooknum, void *nick);
19
20void _init() {
21 int i;
22
23 for (i=0;i<=MAXLOCALUSER;i++) {
24 umhandlers[i]=NULL;
25 }
26 currentlocalunum=1;
27 registerhook(HOOK_IRC_SENDBURSTNICKS,&sendnickburst);
28 registerhook(HOOK_NICK_LOSTNICK,&checklocalkill);
29 registerserverhandler("P",&handleprivatemsgcmd,2);
30 registerserverhandler("O",&handleprivatenoticecmd, 2);
31}
32
33/*
34 * registerlocaluser:
35 * This function creates a local user, and broadcasts it's existence to the net (if connected).
36 */
37
38nick *registerlocaluser(char *nickname, char *ident, char *host, char *realname, char *authname, flag_t umodes, UserMessageHandler handler) {
39 int i;
40 nick *newuser,*np;
41
42 i=0;
95ee3dac 43 currentlocalunum=(currentlocalunum+1)%262142;
c86edd1d
Q
44 while (servernicks[numerictolong(mynumeric->content,2)][currentlocalunum&MAXLOCALUSER]!=NULL) {
45 /* Numeric 262143 on our server is used for "nouser" by the channels module, so cannot be allocated */
46 currentlocalunum=(currentlocalunum+1)%262142;
47 if (++i>MAXLOCALUSER) {
48 return NULL;
49 }
50 }
51
52 /* This code is very similar to stuff in nick.c... */
53 newuser=newnick();
54 newuser->numeric=(numerictolong(mynumeric->content,2)<<18)|(currentlocalunum);
55 strncpy(newuser->nick,nickname,NICKLEN);
56 newuser->nick[NICKLEN]='\0';
57 strncpy(newuser->ident,ident,USERLEN);
58 newuser->ident[USERLEN]='\0';
59 newuser->host=findorcreatehost(host);
60 newuser->realname=findorcreaterealname(realname);
61 newuser->nextbyhost=newuser->host->nicks;
62 newuser->host->nicks=newuser;
63 newuser->nextbyrealname=newuser->realname->nicks;
64 newuser->realname->nicks=newuser;
65 newuser->umodes=umodes;
66 newuser->ipaddress=(127<<24)+(1<<8)+((currentlocalunum%253)+1); /* Make it look like a valid addr on 127.0.1.0/24 */
67 newuser->timestamp=getnettime();
68 newuser->shident=NULL;
69 newuser->sethost=NULL;
70 newuser->marker=0;
71 memset(newuser->exts, 0, MAXNICKEXTS * sizeof(void *));
72
73 if (IsAccount(newuser)) {
74 strncpy(newuser->authname,authname,ACCOUNTLEN);
75 } else {
76 newuser->authname[0]='\0';
77 }
78
79 if (connected) {
80 /* Check for nick collision */
81 if ((np=getnickbynick(nickname))!=NULL) {
82 /* Make sure we will win the collision */
83 newuser->timestamp=(np->timestamp-1);
84 killuser(NULL, np, "Nick collision");
85 }
86 sendnickmsg(newuser);
87 }
88
89 if (handler!=NULL) {
90 umhandlers[(currentlocalunum&MAXLOCALUSER)]=handler;
91 }
92
93 *(gethandlebynumeric(newuser->numeric))=newuser;
94 addnicktohash(newuser);
95 triggerhook(HOOK_NICK_NEWNICK,newuser);
96
97 return newuser;
98}
99
100/*
101 * renamelocaluser:
102 * This function changes the name of a given local user
103 */
104
105int renamelocaluser(nick *np, char *newnick) {
106 nick *np2;
107 time_t timestamp=getnettime();
108
109 if (!np)
110 return -1;
111
112 if (strlen(newnick) > NICKLEN)
113 return -1;
114
115 if (homeserver(np->numeric)!=mylongnum)
116 return -1;
117
118 if ((np2=getnickbynick(newnick))) {
119 if (np2==np) {
120 /* Case only name change */
121 strncpy(np->nick,newnick,NICKLEN);
122 np->nick[NICKLEN]='\0';
123 irc_send("%s N %s %d",longtonumeric(np->numeric,5),np->nick,np->timestamp);
124 triggerhook(HOOK_NICK_RENAME,np);
125 return 0;
126 } else {
127 /* Kill other user and drop through */
128 timestamp=np2->timestamp-1;
129 killuser(NULL, np2, "Nick collision");
130 }
131 }
132
133 np->timestamp=timestamp;
134 removenickfromhash(np);
135 strncpy(np->nick,newnick,NICKLEN);
136 np->nick[NICKLEN]='\0';
137 addnicktohash(np);
138 irc_send("%s N %s %d",longtonumeric(np->numeric,5),np->nick,np->timestamp);
139 triggerhook(HOOK_NICK_RENAME,np);
140
141 return 0;
142}
143
144/*
145 * deregisterlocaluser:
146 * This function removes the given local user from the network
147 */
148
149int deregisterlocaluser(nick *np, char *reason) {
150 int defaultreason=0;
151 long numeric;
152
153 if (np==NULL || (homeserver(np->numeric)!=mylongnum)) {
154 /* Non-existent user, or user not on this server */
155 return -1;
156 }
157
158 if (reason==NULL || *reason=='\0') {
159 defaultreason=1;
160 }
161
162 numeric=np->numeric;
163 umhandlers[np->numeric&MAXLOCALUSER]=NULL;
164 deletenick(np);
165 if (connected) {
166 irc_send("%s Q :Quit: %s",longtonumeric(numeric,5),(defaultreason?"Leaving":reason));
167 }
168
169 return 0;
170}
171
c5f1f827
CP
172/*
173 * hooklocaluserhandler:
174 * This function adds a new handler to the hook chain for a local user
175 * THIS RELIES ON MODULES BEING UNLOADED IN THE CORRECT ORDER.
176 */
177UserMessageHandler hooklocaluserhandler(nick *np, UserMessageHandler newhandler) {
178 UserMessageHandler oldhandler = NULL;
179 if (np==NULL || (homeserver(np->numeric)!=mylongnum)) {
180 /* Non-existent user, or user not on this server */
181 return NULL;
182 }
183 oldhandler = umhandlers[np->numeric&MAXLOCALUSER];
184 umhandlers[np->numeric&MAXLOCALUSER]=newhandler;
185 return oldhandler;
186}
187
c86edd1d
Q
188/*
189 * sendnickmsg:
190 * Sends details of a given local nick to the network.
191 */
192
193void sendnickmsg(nick *np) {
194 char numericbuf[6];
195
196 strncpy(numericbuf,longtonumeric(np->numeric,5),5);
197 numericbuf[5]='\0';
198
199 irc_send("%s N %s 1 %ld %s %s %s%s%s %s %s :%s",
200 mynumeric->content,np->nick,np->timestamp,np->ident,np->host->name->content,
201 printflags(np->umodes,umodeflags),IsAccount(np)?" ":"",
202 np->authname,longtonumeric(np->ipaddress,6),numericbuf,
203 np->realname->name->content);
204}
205
206void sendnickburst(int hooknum, void *arg) {
207 /* Send nick messages for all local users */
208 nick **nh;
209 int i;
210
211 nh=servernicks[numerictolong(mynumeric->content,2)];
212 for (i=0;i<=MAXLOCALUSER;i++) {
213 if (nh[i]!=NULL) {
214 sendnickmsg(nh[i]);
215 }
216 }
217}
218
219/* Check for a kill of a local user */
220void checklocalkill(int hooknum, void *target) {
221 long numeric;
222 void *args[1];
223
224 args[0]=NULL;
225
226 numeric=((nick *)target)->numeric;
227
228 if (homeserver(numeric)==mylongnum) {
229 if (umhandlers[(numeric)&MAXLOCALUSER]!=NULL) {
230 (umhandlers[(numeric)&MAXLOCALUSER])((nick *)target,LU_KILLED,args);
231 }
232 }
233}
234
235int handleprivatemsgcmd(void *source, int cargc, char **cargv) {
236 return handlemessageornotice(source, cargc, cargv, 0);
237}
238
239int handleprivatenoticecmd(void *source, int cargc, char **cargv) {
240 return handlemessageornotice(source, cargc, cargv, 1);
241}
242
243/* Handle privmsg or notice command addressed to user */
244int handlemessageornotice(void *source, int cargc, char **cargv, int isnotice) {
245 nick *sender;
246 nick *target;
247 char *ch;
248 char targetnick[NICKLEN+1];
249 int foundat;
250 void *nargs[2];
251 int i;
252
253 /* Should have target and message */
254 if (cargc<2) {
255 return CMD_OK;
256 }
257
258 if (cargv[0][0]=='#' || cargv[0][0]=='+') {
259 /* Channel message/notice */
260 return CMD_OK;
261 }
262
263 if ((sender=getnickbynumericstr((char *)source))==NULL) {
264 Error("localuser",ERR_WARNING,"PRIVMSG from non existant user %s",(char *)source);
265 return CMD_OK;
266 }
267
268 /* Check for a "secure" message (foo@bar) */
269 foundat=0;
270 for (i=0,ch=cargv[0];(i<=NICKLEN) && (*ch);i++,ch++) {
271 if (*ch=='@') {
272 targetnick[i]='\0';
273 foundat=1;
274 break;
275 } else {
276 targetnick[i]=*ch;
277 }
278 }
279
280 if (!foundat) { /* Didn't find an @ sign, assume it's a numeric */
281 if ((target=getnickbynumericstr(cargv[0]))==NULL) {
282 Error("localuser",ERR_DEBUG,"Couldn't find target for %s",cargv[0]);
283 return CMD_OK;
284 }
285 } else { /* Did find @, do a lookup by nick */
286 if ((target=getnickbynick(targetnick))==NULL) {
287 Error("localuser",ERR_DEBUG,"Couldn't find target for %s",cargv[0]);
bc81aa36 288 irc_send(":%s 401 %s %s :No such nick",myserver->content,sender->nick,cargv[0]);
c86edd1d
Q
289 return CMD_OK;
290 }
291 }
292
293 if (homeserver(target->numeric)!=mylongnum) {
294 Error("localuser",ERR_WARNING,"Got message/notice for someone not on my server");
bc81aa36
C
295 irc_send(":%s 401 %s %s :No such nick",myserver->content,sender->nick,cargv[0]);
296 return CMD_OK;
297 }
298
299 if (foundat && !IsService(target)) {
300 Error("localuser",ERR_DEBUG,"Received secure message for %s, but user is not a service",cargv[0]);
301 irc_send(":%s 401 %s %s :No such nick",myserver->content,sender->nick,cargv[0]);
c86edd1d
Q
302 return CMD_OK;
303 }
304
305 if (umhandlers[(target->numeric)&MAXLOCALUSER]==NULL) {
306 /* No handler anyhow.. */
307 return CMD_OK;
308 }
309
310 /* Dispatch the message. */
311 nargs[0]=(void *)sender;
312 nargs[1]=(void *)cargv[1];
313 (umhandlers[(target->numeric)&MAXLOCALUSER])(target,isnotice?LU_PRIVNOTICE:(foundat?LU_SECUREMSG:LU_PRIVMSG),nargs);
314
315 return CMD_OK;
316}
317
318/* Send message to user */
319void sendmessagetouser(nick *source, nick *target, char *format, ... ) {
320 char buf[BUFSIZE];
321 char senderstr[6];
322 va_list va;
323
324 longtonumeric2(source->numeric,5,senderstr);
325
326 va_start(va,format);
327 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
328 /* So max sendable message is 495 bytes. Of course, a client won't be able
329 * to receive this.. */
330
331 vsnprintf(buf,BUFSIZE-17,format,va);
332 va_end(va);
333
334 if (homeserver(target->numeric)!=mylongnum)
335 irc_send("%s P %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
336}
337
338/* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
339void sendsecuremessagetouser(nick *source, nick *target, char *servername, char *format, ... ) {
340 char buf[BUFSIZE];
341 char senderstr[6];
342 va_list va;
343
344 longtonumeric2(source->numeric,5,senderstr);
345
346 va_start(va,format);
347 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
348 /* So max sendable message is 495 bytes. Of course, a client won't be able
349 * to receive this.. */
350
351 vsnprintf(buf,BUFSIZE-17,format,va);
352 va_end(va);
353
354 if (homeserver(target->numeric)!=mylongnum)
355 irc_send("%s P %s@%s :%s",senderstr,target->nick,servername,buf);
356}
357
358/* Send notice to user */
359void sendnoticetouser(nick *source, nick *target, char *format, ... ) {
360 char buf[BUFSIZE];
361 char senderstr[6];
362 va_list va;
363
364 longtonumeric2(source->numeric,5,senderstr);
365
366 va_start(va,format);
367 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
368 /* So max sendable message is 495 bytes. Of course, a client won't be able
369 * to receive this.. */
370
371 vsnprintf(buf,BUFSIZE-17,format,va);
372 va_end(va);
373
374 if (homeserver(target->numeric)!=mylongnum)
375 irc_send("%s O %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
376}
377
378/* Kill user */
379void killuser(nick *source, nick *target, char *format, ... ) {
380 char buf[BUFSIZE];
381 char senderstr[6];
382 char sourcestring[NICKLEN+USERLEN+3];
383 va_list va;
384
385 if (!source) {
386 /* If we have a null nick, use the server.. */
387 strcpy(senderstr, mynumeric->content);
388 strcpy(sourcestring, myserver->content);
389 } else {
390 strcpy(senderstr, longtonumeric(source->numeric,5));
391 sprintf(sourcestring,"%s!%s",source->host->name->content, source->nick);
392 }
393
394 va_start(va, format);
395 vsnprintf(buf, BUFSIZE-17, format, va);
396 va_end (va);
397
398 irc_send("%s D %s :%s (%s)",senderstr,longtonumeric(target->numeric,5),sourcestring,buf);
399 deletenick(target);
400}
401
402/* Auth user */
403void localusersetaccount(nick *np, char *accname) {
404 if (IsAccount(np)) {
405 Error("localuser",ERR_WARNING,"Tried to set account on user %s already authed", np->nick);
406 return;
407 }
408
409 SetAccount(np);
410 strncpy(np->authname, accname, ACCOUNTLEN);
411 np->authname[ACCOUNTLEN]='\0';
412
413 if (connected) {
414 irc_send("%s AC %s %s %ld",mynumeric->content, longtonumeric(np->numeric,5), np->authname, getnettime());
415 }
416
417 triggerhook(HOOK_NICK_ACCOUNT, np);
418}
419