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