]> jfr.im git - irc/quakenet/newserv.git/blame - localuser/localuser.c
Sigh
[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
0a55e401 16MODULE_VERSION("$Id: localuser.c 663 2006-05-16 17:27:36Z newserv $")
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);
31 registerhook(HOOK_NICK_LOSTNICK,&checklocalkill);
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 */
223void checklocalkill(int hooknum, void *target) {
224 long numeric;
225 void *args[1];
226
227 args[0]=NULL;
228
229 numeric=((nick *)target)->numeric;
230
231 if (homeserver(numeric)==mylongnum) {
232 if (umhandlers[(numeric)&MAXLOCALUSER]!=NULL) {
233 (umhandlers[(numeric)&MAXLOCALUSER])((nick *)target,LU_KILLED,args);
234 }
235 }
236}
237
238int handleprivatemsgcmd(void *source, int cargc, char **cargv) {
239 return handlemessageornotice(source, cargc, cargv, 0);
240}
241
242int handleprivatenoticecmd(void *source, int cargc, char **cargv) {
243 return handlemessageornotice(source, cargc, cargv, 1);
244}
245
246/* Handle privmsg or notice command addressed to user */
247int handlemessageornotice(void *source, int cargc, char **cargv, int isnotice) {
248 nick *sender;
249 nick *target;
250 char *ch;
251 char targetnick[NICKLEN+1];
252 int foundat;
253 void *nargs[2];
254 int i;
255
256 /* Should have target and message */
257 if (cargc<2) {
258 return CMD_OK;
259 }
260
261 if (cargv[0][0]=='#' || cargv[0][0]=='+') {
262 /* Channel message/notice */
263 return CMD_OK;
264 }
265
266 if ((sender=getnickbynumericstr((char *)source))==NULL) {
267 Error("localuser",ERR_WARNING,"PRIVMSG from non existant user %s",(char *)source);
268 return CMD_OK;
269 }
270
271 /* Check for a "secure" message (foo@bar) */
272 foundat=0;
273 for (i=0,ch=cargv[0];(i<=NICKLEN) && (*ch);i++,ch++) {
274 if (*ch=='@') {
275 targetnick[i]='\0';
276 foundat=1;
277 break;
278 } else {
279 targetnick[i]=*ch;
280 }
281 }
282
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]);
286 return CMD_OK;
287 }
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]);
bc81aa36 291 irc_send(":%s 401 %s %s :No such nick",myserver->content,sender->nick,cargv[0]);
c86edd1d
Q
292 return CMD_OK;
293 }
294 }
295
296 if (homeserver(target->numeric)!=mylongnum) {
297 Error("localuser",ERR_WARNING,"Got message/notice for someone not on my server");
bc81aa36
C
298 irc_send(":%s 401 %s %s :No such nick",myserver->content,sender->nick,cargv[0]);
299 return CMD_OK;
300 }
301
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]);
c86edd1d
Q
305 return CMD_OK;
306 }
307
308 if (umhandlers[(target->numeric)&MAXLOCALUSER]==NULL) {
309 /* No handler anyhow.. */
310 return CMD_OK;
311 }
312
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);
317
318 return CMD_OK;
319}
320
321/* Send message to user */
322void sendmessagetouser(nick *source, nick *target, char *format, ... ) {
323 char buf[BUFSIZE];
324 char senderstr[6];
325 va_list va;
326
327 longtonumeric2(source->numeric,5,senderstr);
328
329 va_start(va,format);
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.. */
333
334 vsnprintf(buf,BUFSIZE-17,format,va);
335 va_end(va);
336
337 if (homeserver(target->numeric)!=mylongnum)
338 irc_send("%s P %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
339}
340
341/* Send messageto server, we don't check, but noones going to want to put a server pointer in anyway... */
342void sendsecuremessagetouser(nick *source, nick *target, char *servername, char *format, ... ) {
343 char buf[BUFSIZE];
344 char senderstr[6];
345 va_list va;
346
347 longtonumeric2(source->numeric,5,senderstr);
348
349 va_start(va,format);
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.. */
353
354 vsnprintf(buf,BUFSIZE-17,format,va);
355 va_end(va);
356
357 if (homeserver(target->numeric)!=mylongnum)
358 irc_send("%s P %s@%s :%s",senderstr,target->nick,servername,buf);
359}
360
361/* Send notice to user */
362void sendnoticetouser(nick *source, nick *target, char *format, ... ) {
363 char buf[BUFSIZE];
364 char senderstr[6];
365 va_list va;
366
367 longtonumeric2(source->numeric,5,senderstr);
368
369 va_start(va,format);
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.. */
373
374 vsnprintf(buf,BUFSIZE-17,format,va);
375 va_end(va);
376
377 if (homeserver(target->numeric)!=mylongnum)
378 irc_send("%s O %s :%s",senderstr,longtonumeric(target->numeric,5),buf);
379}
380
381/* Kill user */
382void killuser(nick *source, nick *target, char *format, ... ) {
383 char buf[BUFSIZE];
384 char senderstr[6];
385 char sourcestring[NICKLEN+USERLEN+3];
386 va_list va;
387
388 if (!source) {
389 /* If we have a null nick, use the server.. */
390 strcpy(senderstr, mynumeric->content);
391 strcpy(sourcestring, myserver->content);
392 } else {
393 strcpy(senderstr, longtonumeric(source->numeric,5));
394 sprintf(sourcestring,"%s!%s",source->host->name->content, source->nick);
395 }
396
397 va_start(va, format);
398 vsnprintf(buf, BUFSIZE-17, format, va);
399 va_end (va);
400
401 irc_send("%s D %s :%s (%s)",senderstr,longtonumeric(target->numeric,5),sourcestring,buf);
402 deletenick(target);
403}
404
405/* Auth user */
406void localusersetaccount(nick *np, char *accname) {
407 if (IsAccount(np)) {
408 Error("localuser",ERR_WARNING,"Tried to set account on user %s already authed", np->nick);
409 return;
410 }
411
412 SetAccount(np);
413 strncpy(np->authname, accname, ACCOUNTLEN);
414 np->authname[ACCOUNTLEN]='\0';
415
416 if (connected) {
417 irc_send("%s AC %s %s %ld",mynumeric->content, longtonumeric(np->numeric,5), np->authname, getnettime());
418 }
419
420 triggerhook(HOOK_NICK_ACCOUNT, np);
421}
422