]> jfr.im git - irc/quakenet/newserv.git/blame - localuser/localuser.c
Readded reuse numeric fix, forgot to copy it over from the various independent branch...
[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
172/*
173 * sendnickmsg:
174 * Sends details of a given local nick to the network.
175 */
176
177void sendnickmsg(nick *np) {
178 char numericbuf[6];
179
180 strncpy(numericbuf,longtonumeric(np->numeric,5),5);
181 numericbuf[5]='\0';
182
183 irc_send("%s N %s 1 %ld %s %s %s%s%s %s %s :%s",
184 mynumeric->content,np->nick,np->timestamp,np->ident,np->host->name->content,
185 printflags(np->umodes,umodeflags),IsAccount(np)?" ":"",
186 np->authname,longtonumeric(np->ipaddress,6),numericbuf,
187 np->realname->name->content);
188}
189
190void sendnickburst(int hooknum, void *arg) {
191 /* Send nick messages for all local users */
192 nick **nh;
193 int i;
194
195 nh=servernicks[numerictolong(mynumeric->content,2)];
196 for (i=0;i<=MAXLOCALUSER;i++) {
197 if (nh[i]!=NULL) {
198 sendnickmsg(nh[i]);
199 }
200 }
201}
202
203/* Check for a kill of a local user */
204void checklocalkill(int hooknum, void *target) {
205 long numeric;
206 void *args[1];
207
208 args[0]=NULL;
209
210 numeric=((nick *)target)->numeric;
211
212 if (homeserver(numeric)==mylongnum) {
213 if (umhandlers[(numeric)&MAXLOCALUSER]!=NULL) {
214 (umhandlers[(numeric)&MAXLOCALUSER])((nick *)target,LU_KILLED,args);
215 }
216 }
217}
218
219int handleprivatemsgcmd(void *source, int cargc, char **cargv) {
220 return handlemessageornotice(source, cargc, cargv, 0);
221}
222
223int handleprivatenoticecmd(void *source, int cargc, char **cargv) {
224 return handlemessageornotice(source, cargc, cargv, 1);
225}
226
227/* Handle privmsg or notice command addressed to user */
228int handlemessageornotice(void *source, int cargc, char **cargv, int isnotice) {
229 nick *sender;
230 nick *target;
231 char *ch;
232 char targetnick[NICKLEN+1];
233 int foundat;
234 void *nargs[2];
235 int i;
236
237 /* Should have target and message */
238 if (cargc<2) {
239 return CMD_OK;
240 }
241
242 if (cargv[0][0]=='#' || cargv[0][0]=='+') {
243 /* Channel message/notice */
244 return CMD_OK;
245 }
246
247 if ((sender=getnickbynumericstr((char *)source))==NULL) {
248 Error("localuser",ERR_WARNING,"PRIVMSG from non existant user %s",(char *)source);
249 return CMD_OK;
250 }
251
252 /* Check for a "secure" message (foo@bar) */
253 foundat=0;
254 for (i=0,ch=cargv[0];(i<=NICKLEN) && (*ch);i++,ch++) {
255 if (*ch=='@') {
256 targetnick[i]='\0';
257 foundat=1;
258 break;
259 } else {
260 targetnick[i]=*ch;
261 }
262 }
263
264 if (!foundat) { /* Didn't find an @ sign, assume it's a numeric */
265 if ((target=getnickbynumericstr(cargv[0]))==NULL) {
266 Error("localuser",ERR_DEBUG,"Couldn't find target for %s",cargv[0]);
267 return CMD_OK;
268 }
269 } else { /* Did find @, do a lookup by nick */
270 if ((target=getnickbynick(targetnick))==NULL) {
271 Error("localuser",ERR_DEBUG,"Couldn't find target for %s",cargv[0]);
272 return CMD_OK;
273 }
274 }
275
276 if (homeserver(target->numeric)!=mylongnum) {
277 Error("localuser",ERR_WARNING,"Got message/notice for someone not on my server");
278 return CMD_OK;
279 }
280
281 if (umhandlers[(target->numeric)&MAXLOCALUSER]==NULL) {
282 /* No handler anyhow.. */
283 return CMD_OK;
284 }
285
286 /* Dispatch the message. */
287 nargs[0]=(void *)sender;
288 nargs[1]=(void *)cargv[1];
289 (umhandlers[(target->numeric)&MAXLOCALUSER])(target,isnotice?LU_PRIVNOTICE:(foundat?LU_SECUREMSG:LU_PRIVMSG),nargs);
290
291 return CMD_OK;
292}
293
294/* Send message to user */
295void sendmessagetouser(nick *source, nick *target, char *format, ... ) {
296 char buf[BUFSIZE];
297 char senderstr[6];
298 va_list va;
299
300 longtonumeric2(source->numeric,5,senderstr);
301
302 va_start(va,format);
303 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
304 /* So max sendable message is 495 bytes. Of course, a client won't be able
305 * to receive this.. */
306
307 vsnprintf(buf,BUFSIZE-17,format,va);
308 va_end(va);
309
310 if (homeserver(target->numeric)!=mylongnum)
311 irc_send("%s P %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
312}
313
314/* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
315void sendsecuremessagetouser(nick *source, nick *target, char *servername, char *format, ... ) {
316 char buf[BUFSIZE];
317 char senderstr[6];
318 va_list va;
319
320 longtonumeric2(source->numeric,5,senderstr);
321
322 va_start(va,format);
323 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
324 /* So max sendable message is 495 bytes. Of course, a client won't be able
325 * to receive this.. */
326
327 vsnprintf(buf,BUFSIZE-17,format,va);
328 va_end(va);
329
330 if (homeserver(target->numeric)!=mylongnum)
331 irc_send("%s P %s@%s :%s",senderstr,target->nick,servername,buf);
332}
333
334/* Send notice to user */
335void sendnoticetouser(nick *source, nick *target, char *format, ... ) {
336 char buf[BUFSIZE];
337 char senderstr[6];
338 va_list va;
339
340 longtonumeric2(source->numeric,5,senderstr);
341
342 va_start(va,format);
343 /* 10 bytes of numeric, 5 bytes of fixed format + terminator = 17 bytes */
344 /* So max sendable message is 495 bytes. Of course, a client won't be able
345 * to receive this.. */
346
347 vsnprintf(buf,BUFSIZE-17,format,va);
348 va_end(va);
349
350 if (homeserver(target->numeric)!=mylongnum)
351 irc_send("%s O %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
352}
353
354/* Kill user */
355void killuser(nick *source, nick *target, char *format, ... ) {
356 char buf[BUFSIZE];
357 char senderstr[6];
358 char sourcestring[NICKLEN+USERLEN+3];
359 va_list va;
360
361 if (!source) {
362 /* If we have a null nick, use the server.. */
363 strcpy(senderstr, mynumeric->content);
364 strcpy(sourcestring, myserver->content);
365 } else {
366 strcpy(senderstr, longtonumeric(source->numeric,5));
367 sprintf(sourcestring,"%s!%s",source->host->name->content, source->nick);
368 }
369
370 va_start(va, format);
371 vsnprintf(buf, BUFSIZE-17, format, va);
372 va_end (va);
373
374 irc_send("%s D %s :%s (%s)",senderstr,longtonumeric(target->numeric,5),sourcestring,buf);
375 deletenick(target);
376}
377
378/* Auth user */
379void localusersetaccount(nick *np, char *accname) {
380 if (IsAccount(np)) {
381 Error("localuser",ERR_WARNING,"Tried to set account on user %s already authed", np->nick);
382 return;
383 }
384
385 SetAccount(np);
386 strncpy(np->authname, accname, ACCOUNTLEN);
387 np->authname[ACCOUNTLEN]='\0';
388
389 if (connected) {
390 irc_send("%s AC %s %s %ld",mynumeric->content, longtonumeric(np->numeric,5), np->authname, getnettime());
391 }
392
393 triggerhook(HOOK_NICK_ACCOUNT, np);
394}
395