]>
jfr.im git - irc/quakenet/newserv.git/blob - noperserv/noperserv_fakeuser.c
2 * NOperserv Fakeuser module
4 * Allows fakeusers to be added so as to block nicks, for example.
6 * Copyright (c) Tim Gordon 2006.
9 #include "../core/schedule.h"
10 #include "../localuser/localuser.h"
11 #include "../localuser/localuserchannel.h"
12 #include "../irc/irc_config.h"
13 #include "../lib/irc_string.h"
14 #include "../control/control.h"
15 #include "../channel/channel.h"
16 #include "../pqsql/pqsql.h"
17 #include "../lib/strlfunc.h"
18 #include "../lib/version.h"
23 MODULE_VERSION("$Id: noperserv_fakeuser.c 663 2006-05-16 17:27:36Z newserv $")
25 /* #define SIT_CHANNEL "#qnet.fakeusers" */
29 typedef struct fakeuser
{
32 struct fakeuser
*next
;
35 typedef struct user_details
{
36 char nick
[NICKLEN
+ 1];
37 char ident
[USERLEN
+ 1];
38 char host
[HOSTLEN
+ 1];
39 char realname
[REALLEN
+ 1];
41 struct user_details
*next
;
45 fakeuser
*fakeuserlist
= NULL
;
46 user_details
*killeduserlist
= NULL
;
47 int fakeusercount
= 0;
48 int killedusercount
= 0;
50 void fakeuser_cleanup();
51 int fakeuser_loaddb();
52 void fakeusers_load(PGconn
*dbconn
, void *tag
);
53 void fakeuser_handler(nick
*user
, int command
, void **params
);
54 int fakeadd(void *sender
, int cargc
, char **cargv
);
55 int fakelist(void *sender
, int cargc
, char **cargv
);
56 int fakekill(void *sender
, int cargc
, char **cargv
);
57 void reconnectfake(void *details
);
60 if (!fakeuser_loaddb())
62 Error("noperserv_fakeuser", ERR_ERROR
, "Cannot load database");
65 registercontrolhelpcmd("fakeuser", NO_OPER
, 4, &fakeadd
, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
66 registercontrolhelpcmd("fakelist", NO_OPER
, 0, &fakelist
, "Usage: FAKELIST\nLists all fake users.");
67 registercontrolhelpcmd("fakekill", NO_OPER
, 2, &fakekill
, "Usage: FAKEKILL nick <reason>\nRemoves a fake user");
72 deregistercontrolcmd("fakeuser", &fakeadd
);
73 deregistercontrolcmd("fakelist", &fakelist
);
74 deregistercontrolcmd("fakekill", &fakekill
);
77 void fakeuser_cleanup()
82 for (fake
= fakeuserlist
; fake
; fake
= next
)
84 deregisterlocaluser(fake
->user
, "Signing off");
88 for (killed
= killeduserlist
; killed
; killed
= next
)
90 deleteschedule(killed
->schedule
, &reconnectfake
, killed
);
96 killeduserlist
= NULL
;
104 pqcreatequery("CREATE TABLE noperserv.fakeusers ("
105 "nick VARCHAR(%d) NOT NULL,"
106 "ident VARCHAR(%d) NOT NULL,"
107 "host VARCHAR(%d) NOT NULL,"
108 "realname VARCHAR(%d) NOT NULL,"
109 "PRIMARY KEY (nick))", NICKLEN
, USERLEN
, HOSTLEN
, REALLEN
);
110 pqasyncquery(&fakeusers_load
, NULL
, "SELECT nick, ident, host, realname FROM noperserv.fakeusers");
114 void fakeusers_load(PGconn
*dbconn
, void *tag
)
116 PGresult
*pgres
= PQgetResult(dbconn
);
117 user_details details
;
120 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
121 Error("noperserv_fakeuser", ERR_ERROR
, "Error loading fakeuser list (%d)", PQresultStatus(pgres
));
124 details
.schedule
= NULL
;
125 rowcount
= PQntuples(pgres
);
126 Error("noperserv_fakeuser", ERR_INFO
, "Loading %d users", rowcount
);
128 details
.lastkill
= 0;
130 for (i
= 0; i
< rowcount
; i
++)
132 strlcpy(details
.nick
, PQgetvalue(pgres
, i
, 0), NICKLEN
+ 1);
133 strlcpy(details
.ident
, PQgetvalue(pgres
, i
, 1), USERLEN
+ 1);
134 strlcpy(details
.host
, PQgetvalue(pgres
, i
, 2), HOSTLEN
+ 1);
135 strlcpy(details
.realname
, PQgetvalue(pgres
, i
, 3), REALLEN
+ 1);
136 reconnectfake(&details
);
140 user_details
*getdetails(nick
*user
)
142 user_details
*details
;
143 details
= malloc(sizeof(user_details
));
146 details
->schedule
= NULL
;
147 strlcpy(details
->nick
, user
->nick
, NICKLEN
+ 1);
148 strlcpy(details
->ident
, user
->ident
, USERLEN
+ 1);
149 strlcpy(details
->host
, user
->host
->name
->content
, HOSTLEN
+ 1);
150 strlcpy(details
->realname
, user
->realname
->name
->content
, REALLEN
+ 1);
151 details
->lastkill
= 0;
157 #define ERR_WONTKILL 3
160 nick
*register_fakeuser(user_details
*details
)
163 if((user
= getnickbynick(details
->nick
)) && (IsOper(user
) || IsService(user
) || IsXOper(user
))) {
164 err_code
= ERR_WONTKILL
;
169 return registerlocaluser(details
->nick
, details
->ident
, details
->host
, details
->realname
,
170 NULL
, UMODE_INV
| UMODE_DEAF
, &fakeuser_handler
);
173 fakeuser
*ll_add(user_details
*details
) //Adds to the (sorted) linked list
175 fakeuser
*fake
, *newfake
;
180 cmp
= ircd_strcmp(details
->nick
, fakeuserlist
->user
->nick
);
183 err_code
= ERR_EXISTS
;
191 newfake
= malloc(sizeof(fakeuser
));
198 newfake
->user
= register_fakeuser(details
);
202 /* errcode already set by register_fakeuser */
205 newfake
->lastkill
= details
->lastkill
;
206 newfake
->next
= fakeuserlist
;
207 fakeuserlist
= newfake
;
211 for (fake
= fakeuserlist
; fake
->next
; fake
= fake
->next
)
213 cmp
= ircd_strcmp(details
->nick
, fake
->next
->user
->nick
);
216 err_code
= ERR_EXISTS
;
221 newfake
= malloc(sizeof(fakeuser
));
227 newfake
->user
= register_fakeuser(details
);
231 /* errcode already set by register_fakeuser */
234 newfake
->lastkill
= details
->lastkill
;
235 newfake
->next
= fake
->next
;
236 fake
->next
= newfake
;
241 newfake
= malloc(sizeof(fakeuser
));
247 newfake
->user
= register_fakeuser(details
);
251 /* errcode already set by register_fakeuser */
254 newfake
->lastkill
= details
->lastkill
;
255 newfake
->next
= NULL
;
256 fake
->next
= newfake
;
261 void kll_add(user_details
*details
) //Adds to the (sorted) linked list of killed users
264 user_details
*killed
;
267 cmp
= ircd_strcmp(details
->nick
, killeduserlist
->nick
);
270 if (cmp
< 0) //Add to the start of the list
272 details
->next
= killeduserlist
;
273 killeduserlist
= details
;
277 for (killed
= killeduserlist
; killed
->next
; killed
= killed
->next
)
279 cmp
= ircd_strcmp(details
->nick
, killed
->next
->nick
);
282 details
->next
= killed
->next
;
283 killed
->next
= details
;
288 details
->next
= NULL
;
289 killed
->next
= details
;
294 fakeuser
*ll_remove(char *nickname
) //Removes from the linked list
296 fakeuser
*fake
, *rmfake
;
301 cmp
= ircd_strcmp(nickname
, fakeuserlist
->user
->nick
);
306 rmfake
= fakeuserlist
;
307 fakeuserlist
= fakeuserlist
->next
;
312 for (fake
= fakeuserlist
; fake
->next
; fake
= fake
->next
)
315 cmp
= ircd_strcmp(nickname
, rmfake
->user
->nick
);
320 fake
->next
= rmfake
->next
;
329 user_details
*kll_remove(char *nickname
) //Removes from the killed user linked list
331 user_details
*details
, *rmdetails
;
336 cmp
= ircd_strcmp(nickname
, killeduserlist
->nick
);
341 rmdetails
= killeduserlist
;
342 killeduserlist
= killeduserlist
->next
;
343 rmdetails
->next
= NULL
;
347 for (details
= killeduserlist
; details
->next
; details
= details
->next
)
349 rmdetails
= details
->next
;
350 cmp
= ircd_strcmp(nickname
, rmdetails
->nick
);
355 details
->next
= rmdetails
->next
;
356 rmdetails
->next
= NULL
;
364 void fakeuser_handler(nick
*user
, int command
, void **params
)
366 if (command
== LU_KILLED
)
368 user_details
*details
;
370 time_t timenow
= time(NULL
);
372 details
= getdetails(user
);
373 item
= ll_remove(details
->nick
);
377 details
->lastkill
= item
->lastkill
;
380 if(timenow
- item
->lastkill
< KILL_TIME
) {
381 char escnick
[NICKLEN
* 2 + 1];
382 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", details
->nick
, details
->ident
, details
->host
, details
->realname
, KILL_TIME
);
383 item
= ll_remove(details
->nick
);
386 PQescapeString(escnick
, details
->nick
, strlen(details
->nick
));
387 pqquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
390 details
->lastkill
= timenow
;
393 controlwalls(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) was KILL'ed", details->nick,
394 details->ident, details->host, details->realname);
396 details
->schedule
= scheduleoneshot(time(NULL
) + KILL_WAIT
, &reconnectfake
, details
);
397 if (!details
->schedule
)
399 Error("noperserv_fakeuser", ERR_ERROR
, "Couldn't reschedule fakeuser for reconnect");
407 //Usage: FAKEUSER nick <ident> <host> <realname>
408 int fakeadd(void *sender
, int cargc
, char **cargv
)
410 user_details details
, *killed
;
411 char escnick
[NICKLEN
* 2 + 1], escident
[USERLEN
* 2 + 1], eschost
[HOSTLEN
* 2 + 1], escreal
[REALLEN
* 2 + 1];
417 strlcpy(details
.nick
, cargv
[0], NICKLEN
+ 1);
419 strlcpy(details
.realname
, cargv
[0], REALLEN
+ 1);
421 strlcpy(details
.realname
, cargv
[3], REALLEN
+ 1);
424 strlcpy(details
.host
, cargv
[0], NICKLEN
+ 1);
425 strlcat(details
.host
, ".fakeusers.quakenet.org", HOSTLEN
+ 1);
428 strlcpy(details
.host
, cargv
[2], HOSTLEN
+ 1);
430 strlcpy(details
.ident
, cargv
[0], USERLEN
+ 1);
432 strlcpy(details
.ident
, cargv
[1], USERLEN
+ 1);
434 details
.lastkill
= 0;
436 newfake
= ll_add(&details
);
439 if (err_code
== ERR_EXISTS
)
440 controlreply(sender
, "Error: fakeuser already exists");
441 else if (err_code
== ERR_MEM
)
442 controlreply(sender
, "Error: memory error!!");
443 else if (err_code
== ERR_WONTKILL
)
444 controlreply(sender
, "Nick already exists and I won't kill it");
446 controlreply(sender
, "Unknown error when adding fakeuser");
449 newnick
= newfake
->user
;
450 PQescapeString(escnick
, newnick
->nick
, strlen(newnick
->nick
));
451 PQescapeString(escident
, newnick
->ident
, strlen(newnick
->ident
));
452 PQescapeString(eschost
, newnick
->host
->name
->content
, newnick
->host
->name
->length
);
453 PQescapeString(escreal
, newnick
->realname
->name
->content
, newnick
->realname
->name
->length
);
454 if ((killed
= kll_remove(newnick
->nick
))) //Is this nickname scheduled to reconnect?
456 deleteschedule(killed
->schedule
, &reconnectfake
, killed
);
458 pqquery("UPDATE noperserv.fakeusers SET ident = '%s', host = '%s', realname = '%s' WHERE nick = '%s'",
459 escident
, eschost
, escreal
, escnick
);
462 pqquery("INSERT INTO noperserv.fakeusers (nick, ident, host, realname) VALUES ('%s', '%s', '%s', '%s')",
463 escnick
, escident
, eschost
, escreal
);
464 controlreply(sender
, "Added fake user %s", newnick
->nick
);
465 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) added by %s/%s", newnick
->nick
, newnick
->ident
,
466 newnick
->host
->name
->content
, newnick
->realname
->name
->content
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
470 if (!(sitchannel
= findchannel(SIT_CHANNEL
)))
471 sitchannel
= createchannel(SIT_CHANNEL
);
472 localjoinchannel(newnick
, sitchannel
);
479 int fakelist(void *sender
, int cargc
, char **cargv
)
482 if (fakeusercount
== 1)
483 controlreply(sender
, "1 fakeuser is currently connected");
485 controlreply(sender
, "%d fakeusers are currently connected", fakeusercount
);
486 for(fake
= fakeuserlist
; fake
; fake
= fake
->next
)
487 controlreply(sender
, "%s!%s@%s (%s)", fake
->user
->nick
, fake
->user
->ident
,
488 fake
->user
->host
->name
->content
, fake
->user
->realname
->name
->content
);
491 user_details
*k_fake
;
492 if (fakeusercount
== 1)
493 controlreply(sender
, "1 fakeuser is currently waiting to reconnect");
495 controlreply(sender
, "%d fakeusers are currently waiting to reconnect", killedusercount
);
496 for(k_fake
= killeduserlist
; k_fake
; k_fake
= k_fake
->next
)
497 controlreply(sender
, "%s!%s@%s (%s)", k_fake
->nick
, k_fake
->ident
, k_fake
->host
, k_fake
->realname
);
502 //Usage: FAKEKILL nick <reason>
503 int fakekill(void *sender
, int cargc
, char **cargv
)
506 user_details
*k_fake
;
507 char escnick
[NICKLEN
* 2 + 1];
510 if ((fake
= ll_remove(cargv
[0])))
512 PQescapeString(escnick
, fake
->user
->nick
, strlen(fake
->user
->nick
));
513 pqquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
514 controlreply(sender
, "Killed fake user %s", fake
->user
->nick
);
515 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) removed by %s/%s", fake
->user
->nick
, fake
->user
->ident
,
516 fake
->user
->host
->name
->content
, fake
->user
->realname
->name
->content
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
518 deregisterlocaluser(fake
->user
, cargv
[1]);
520 deregisterlocaluser(fake
->user
, "Signing off");
524 if ((k_fake
= kll_remove(cargv
[0]))) //Fakeuser might be waiting to rejoin
526 PQescapeString(escnick
, k_fake
->nick
, strlen(k_fake
->nick
));
527 pqquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
528 controlreply(sender
, "Killed fake user %s", k_fake
->nick
);
529 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) removed by %s/%s", k_fake
->nick
,
530 k_fake
->ident
, k_fake
->host
, k_fake
->realname
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
534 controlreply(sender
, "No fakeuser with that nick exists");
538 void reconnectfake(void *details
)
541 user_details
*u_details
= details
;
542 if (u_details
->schedule
)
543 kll_remove(u_details
->nick
); //Fakeuser was /kill'd
544 fake
= ll_add(u_details
);
545 if (u_details
->schedule
)
552 if (!(sitchannel
= findchannel(SIT_CHANNEL
)))
553 sitchannel
= createchannel(SIT_CHANNEL
);
554 localjoinchannel(fake
->user
, sitchannel
);