2 * This contains Q9's "built in" commands and CTCP handlers
6 #include "../core/schedule.h"
7 #include "../lib/irc_string.h"
8 #include "../pqsql/pqsql.h"
12 int cs_dorehash(void *source
, int cargc
, char **cargv
) {
14 Command
*cmdlist
[200];
17 /* Reload the response text first */
20 /* Now the commands */
21 n
=getcommandlist(cscommands
, cmdlist
, 200);
24 loadcommandsummary(cmdlist
[i
]);
26 chanservstdmessage(sender
, QM_DONE
);
31 int cs_doquit(void *source
, int cargc
, char **cargv
) {
32 char *reason
="Leaving";
33 nick
*sender
=(nick
*)source
;
39 chanservstdmessage(sender
, QM_DONE
);
41 deregisterlocaluser(chanservnick
, reason
);
42 scheduleoneshot(time(NULL
)+1,&chanservreguser
,NULL
);
47 int cs_dorename(void *source
, int cargc
, char **cargv
) {
48 char newnick
[NICKLEN
+1];
52 chanservstdmessage(sender
, QM_NOTENOUGHPARAMS
, "rename");
56 strncpy(newnick
,cargv
[0],NICKLEN
);
57 newnick
[NICKLEN
]='\0';
59 renamelocaluser(chanservnick
, newnick
);
60 chanservstdmessage(sender
, QM_DONE
);
65 int cs_doshowcommands(void *source
, int cargc
, char **cargv
) {
68 Command
*cmdlist
[200];
74 n
=getcommandlist(cscommands
, cmdlist
, 200);
75 rup
=getreguserfromnick(sender
);
82 chanservstdmessage(sender
, QM_COMMANDLIST
);
85 if (cargc
>0 && !match2strings(cargv
[0],cmdlist
[i
]->command
->content
))
88 /* Don't list aliases */
89 if (cmdlist
[i
]->level
& QCMD_ALIAS
)
92 /* Check that this user can use this command.. */
93 if ((cmdlist
[i
]->level
& QCMD_AUTHED
) && !rup
)
96 if ((cmdlist
[i
]->level
& QCMD_NOTAUTHED
) && rup
)
99 if ((cmdlist
[i
]->level
& QCMD_HELPER
) &&
100 (!rup
|| !UHasHelperPriv(rup
)))
103 if ((cmdlist
[i
]->level
& QCMD_OPER
) &&
104 (!rup
|| !UHasOperPriv(rup
) || !IsOper(sender
)))
107 if ((cmdlist
[i
]->level
& QCMD_ADMIN
) &&
108 (!rup
|| !UHasAdminPriv(rup
) || !IsOper(sender
)))
111 if ((cmdlist
[i
]->level
& QCMD_DEV
) &&
112 (!rup
|| !UIsDev(rup
) || !IsOper(sender
)))
115 summary
=(cmdsummary
*)cmdlist
[i
]->ext
;
117 if (summary
->bylang
[lang
]) {
118 message
=summary
->bylang
[lang
]->content
;
119 } else if (summary
->bylang
[0]) {
120 message
=summary
->bylang
[0]->content
;
122 message
=summary
->def
->content
;
125 chanservsendmessage(sender
, "%-20s %s",cmdlist
[i
]->command
->content
, message
);
128 chanservstdmessage(sender
, QM_ENDOFLIST
);
133 int cs_dohelp(void *source
, int cargc
, char **cargv
) {
138 return cs_doshowcommands(source
,cargc
,cargv
);
140 if (!(cmd
=findcommandintree(cscommands
, cargv
[0], 1))) {
141 chanservstdmessage(sender
, QM_UNKNOWNCMD
, cargv
[0]);
145 csdb_dohelp(sender
, cmd
);
151 int cs_doctcpping(void *source
, int cargc
, char **cargv
) {
152 char *nullbuf
="\001";
154 sendnoticetouser(chanservnick
, source
, "%cPING %s",
155 1, cargc
?cargv
[0]:nullbuf
);
160 int cs_doctcpversion(void *source
, int cargc
, char **cargv
) {
161 sendnoticetouser(chanservnick
, source
, "\01VERSION Q9 version %s (Compiled on " __DATE__
") (C) 2002-3 David Mansell (splidge)\01", QVERSION
);
162 sendnoticetouser(chanservnick
, source
, "\01VERSION Built on newserv version 1.00. (C) 2002-3 David Mansell (splidge)\01");
167 int cs_doversion(void *source
, int cargc
, char **cargv
) {
168 chanservsendmessage((nick
*)source
, "Q9 version %s (Compiled on " __DATE__
") (C) 2002-3 David Mansell (splidge)", QVERSION
);
169 chanservsendmessage((nick
*)source
, "Built on newserv version 1.00. (C) 2002-3 David Mansell (splidge)");
173 int cs_doctcpgender(void *source
, int cargc
, char **cargv
) {
174 sendnoticetouser(chanservnick
, source
, "\1GENDER Anyone who has a bitch mode has to be female ;)\1");
179 void csdb_dohelp_real(PGconn
*, void *);
182 unsigned int numeric
;
183 sstring
*commandname
;
187 void csdb_dohelp(nick
*np
, Command
*cmd
) {
188 struct helpinfo
*hip
;
190 hip
=(struct helpinfo
*)malloc(sizeof(struct helpinfo
));
192 hip
->numeric
=np
->numeric
;
193 hip
->commandname
=getsstring(cmd
->command
->content
, cmd
->command
->length
);
195 pqasyncquery(csdb_dohelp_real
, (void *)hip
,
196 "SELECT languageID, fullinfo from help where lower(command)=lower('%s')",cmd
->command
->content
);
199 void csdb_dohelp_real(PGconn
*dbconn
, void *arg
) {
200 struct helpinfo
*hip
=arg
;
201 nick
*np
=getnickbynumeric(hip
->numeric
);
207 pgres
=PQgetResult(dbconn
);
209 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
210 Error("chanserv",ERR_ERROR
,"Error loading help text.");
214 if (PQnfields(pgres
)!=2) {
215 Error("chanserv",ERR_ERROR
,"Help text format error.");
219 num
=PQntuples(pgres
);
223 freesstring(hip
->commandname
);
228 if ((rup
=getreguserfromnick(np
)))
229 lang
=rup
->languageid
;
233 for (i
=0;i
<num
;i
++) {
234 j
=strtoul(PQgetvalue(pgres
,i
,0),NULL
,10);
235 if ((j
==0 && result
==NULL
) || (j
==lang
)) {
236 result
=PQgetvalue(pgres
,i
,1);
237 if(strlen(result
)==0)
243 chanservstdmessage(np
, QM_NOHELP
, hip
->commandname
->content
);
245 chanservsendmessage(np
, result
);
247 freesstring(hip
->commandname
);
251 void csdb_doauthhistory_real(PGconn
*dbconn
,void *arg
);
252 void csdb_dochanlevhistory_real(PGconn
*dbconn
,void *arg
);
253 void csdb_doaccounthistory_real(PGconn
*dbconn
,void *arg
);
254 void csc_dorollbackchan_real(PGconn
*dbconn
,void *arg
);
255 void csdb_dorollbackaccount_real(PGconn
*dbconn
,void *arg
);
257 struct authhistoryinfo
{
258 unsigned int numeric
;
262 void csdb_retreiveauthhistory(nick
*np
, reguser
*rup
, int limit
) {
263 struct authhistoryinfo
*ahi
;
265 ahi
=(struct authhistoryinfo
*)malloc(sizeof(struct authhistoryinfo
));
266 ahi
->numeric
=np
->numeric
;
268 pqasyncquery(csdb_doauthhistory_real
, (void *)ahi
,
269 "SELECT userID, nick, username, host, authtime, disconnecttime from authhistory where "
270 "userID=%u order by authtime desc limit %d", rup
->ID
, limit
);
273 void csdb_doauthhistory_real(PGconn
*dbconn
, void *arg
) {
274 struct authhistoryinfo
*ahi
=(struct authhistoryinfo
*)arg
;
275 nick
*np
=getnickbynumeric(ahi
->numeric
);
277 char *ahnick
, *ahuser
, *ahhost
;
278 time_t ahauthtime
, ahdisconnecttime
;
282 char tbuf1
[15], tbuf2
[15];
284 pgres
=PQgetResult(dbconn
);
286 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
287 Error("chanserv", ERR_ERROR
, "Error loading auth history data.");
291 if (PQnfields(pgres
) != 6) {
292 Error("chanserv", ERR_ERROR
, "Auth history data format error.");
296 num
=PQntuples(pgres
);
304 if (!(rup
=getreguserfromnick(np
))) {
309 chanservstdmessage(np
, QM_AUTHHISTORYHEADER
);
310 for (i
=0; i
<num
; i
++) {
311 if (!UHasHelperPriv(rup
) && (strtoul(PQgetvalue(pgres
, i
, 0), NULL
, 10) != rup
->ID
)) {
316 ahnick
=PQgetvalue(pgres
, i
, 1);
317 ahuser
=PQgetvalue(pgres
, i
, 2);
318 ahhost
=PQgetvalue(pgres
, i
, 3);
319 ahauthtime
=strtoul(PQgetvalue(pgres
, i
, 4), NULL
, 10);
320 ahdisconnecttime
=strtoul(PQgetvalue(pgres
, i
, 5), NULL
, 10);
321 tmp
=localtime(&ahauthtime
);
322 strftime(tbuf1
, 15, "%d/%m/%y %H:%M", tmp
);
323 if (ahdisconnecttime
) {
324 tmp
=localtime(&ahdisconnecttime
);
325 strftime(tbuf2
, 15, "%d/%m/%y %H:%M", tmp
);
327 chanservsendmessage(np
, "#%-6d %-15s %-15s %-15s %s@%s", ++count
, tbuf1
, ahdisconnecttime
?tbuf2
:"never", ahnick
, ahuser
, ahhost
);
329 chanservstdmessage(np
, QM_ENDOFLIST
);
335 void csdb_retreivechanlevhistory(nick
*np
, regchan
*rcp
, time_t starttime
) {
336 pqasyncquery(csdb_dochanlevhistory_real
, (void *)np
->numeric
,
337 "SELECT userID, channelID, targetID, changetime, authtime, oldflags, newflags from chanlevhistory where "
338 "channelID=%u and changetime>%lu order by changetime desc limit 1000", rcp
->ID
, starttime
);
340 void csdb_dochanlevhistory_real(PGconn
*dbconn
, void *arg
) {
341 nick
*np
=getnickbynumeric((unsigned int)arg
);
342 reguser
*rup
, *crup1
, *crup2
;
343 unsigned int userID
, channelID
, targetID
;
344 time_t changetime
, authtime
;
345 flag_t oldflags
, newflags
;
349 char tbuf
[15], fbuf
[18];
351 pgres
=PQgetResult(dbconn
);
353 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
354 Error("chanserv", ERR_ERROR
, "Error loading chanlev history data.");
358 if (PQnfields(pgres
) != 7) {
359 Error("chanserv", ERR_ERROR
, "Chanlev history data format error.");
362 num
=PQntuples(pgres
);
369 if (!(rup
=getreguserfromnick(np
)) || !UHasHelperPriv(rup
)) {
374 chanservsendmessage(np
, "Number: Time: Changing user: Changed user: Old flags: New flags:");
375 for (i
=0; i
<num
; i
++) {
376 userID
=strtoul(PQgetvalue(pgres
, i
, 0), NULL
, 10);
377 channelID
=strtoul(PQgetvalue(pgres
, i
, 1), NULL
, 10);
378 targetID
=strtoul(PQgetvalue(pgres
, i
, 2), NULL
, 10);
379 changetime
=strtoul(PQgetvalue(pgres
, i
, 3), NULL
, 10);
380 authtime
=strtoul(PQgetvalue(pgres
, i
, 4), NULL
, 10);
381 oldflags
=strtoul(PQgetvalue(pgres
, i
, 5), NULL
, 10);
382 newflags
=strtoul(PQgetvalue(pgres
, i
, 6), NULL
, 10);
383 tmp
=localtime(&changetime
);
384 strftime(tbuf
, 15, "%d/%m/%y %H:%M", tmp
);
385 strncpy(fbuf
, printflags(oldflags
, rcuflags
), 17);
387 chanservsendmessage(np
, "#%-6d %-15s %-15s %-15s %-15s %s", ++count
, tbuf
,
388 (crup1
=findreguserbyID(userID
))?crup1
->username
:"Unknown", (crup2
=findreguserbyID(targetID
))?crup2
->username
:"Unknown",
389 fbuf
, printflags(newflags
, rcuflags
));
391 chanservstdmessage(np
, QM_ENDOFLIST
);
396 void csdb_rollbackchanlevhistory(nick
*np
, regchan
*rcp
, reguser
* rup
, time_t starttime
) {
398 pqasyncquery(csc_dorollbackchan_real
, (void *)np
->numeric
,
399 "SELECT userID, channelID, targetID, changetime, authtime, oldflags, newflags from chanlevhistory where "
400 "userID=%u and channelID=%u and changetime>%lu order by changetime desc limit 1000", rup
->ID
, rcp
->ID
, starttime
);
402 pqasyncquery(csc_dorollbackchan_real
, (void *)np
->numeric
,
403 "SELECT userID, channelID, targetID, changetime, authtime, oldflags, newflags from chanlevhistory where "
404 "channelID=%u and changetime>%lu order by changetime desc limit 1000", rcp
->ID
, starttime
);
407 void csc_dorollbackchan_real(PGconn
*dbconn
, void *arg
) {
408 nick
*np
=getnickbynumeric((unsigned int)arg
);
409 reguser
*rup
, *crup1
, *crup2
;
413 unsigned int userID
, channelID
, targetID
;
414 time_t changetime
, authtime
;
415 flag_t oldflags
, newflags
;
417 int i
, j
, num
, count
=0, newuser
;
419 char tbuf
[15], fbuf
[18];
421 pgres
=PQgetResult(dbconn
);
423 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
424 Error("chanserv", ERR_ERROR
, "Error loading chanlev history data.");
428 if (PQnfields(pgres
) != 7) {
429 Error("chanserv", ERR_ERROR
, "Chanlev history data format error.");
433 num
=PQntuples(pgres
);
436 Error("chanserv", ERR_ERROR
, "No nick pointer in rollback.");
440 if (!(rup
=getreguserfromnick(np
)) || !UHasOperPriv(rup
)) {
441 Error("chanserv", ERR_ERROR
, "No reguser pointer or oper privs in rollback.");
446 for (i
=0; i
<num
; i
++) {
447 userID
=strtoul(PQgetvalue(pgres
, i
, 0), NULL
, 10);
448 channelID
=strtoul(PQgetvalue(pgres
, i
, 1), NULL
, 10);
451 for (j
=0; j
<CHANNELHASHSIZE
&& !rcp
; j
++) {
452 for (cip
=chantable
[j
]; cip
&& !rcp
; cip
=cip
->next
) {
453 if (!cip
->exts
[chanservext
])
456 if (((regchan
*)cip
->exts
[chanservext
])->ID
== channelID
)
457 rcp
=(regchan
*)cip
->exts
[chanservext
];
462 Error("chanserv", ERR_ERROR
, "No regchan pointer or oper privs in rollback.");
469 chanservsendmessage(np
, "Attempting to roll back %s:", cip
->name
->content
);
471 targetID
=strtoul(PQgetvalue(pgres
, i
, 2), NULL
, 10);
472 changetime
=strtoul(PQgetvalue(pgres
, i
, 3), NULL
, 10);
473 authtime
=strtoul(PQgetvalue(pgres
, i
, 4), NULL
, 10);
474 oldflags
=strtoul(PQgetvalue(pgres
, i
, 5), NULL
, 10);
475 newflags
=strtoul(PQgetvalue(pgres
, i
, 6), NULL
, 10);
476 strncpy(fbuf
, printflags(newflags
, rcuflags
), 17);
478 crup1
=findreguserbyID(userID
);
479 crup2
=findreguserbyID(targetID
);
482 chanservsendmessage(np
, "Affected user (ID: %d) is no longer in database, continuing...", targetID
);
486 if (!(rcup
=findreguseronchannel(rcp
, crup2
))) {
487 rcup
=getregchanuser();
491 rcup
->changetime
=time(NULL
);
498 csdb_chanlevhistory_insert(rcp
, np
, rcup
->user
, rcup
->flags
, oldflags
);
499 rcup
->flags
=oldflags
;
500 chanservsendmessage(np
, "%s user flags for %s (%s -> %s)", newflags
?oldflags
?"Restoring":"Deleting":"Readding",
501 crup2
->username
, fbuf
, printflags(oldflags
, rcuflags
));
505 addregusertochannel(rcup
);
506 csdb_createchanuser(rcup
);
509 csdb_updatechanuser(rcup
);
513 csdb_deletechanuser(rcup
);
514 delreguserfromchannel(rcp
, crup2
);
517 freesstring(rcup
->info
);
518 freeregchanuser(rcup
);
521 for (j
=0; j
<REGCHANUSERHASHSIZE
; j
++)
522 if (rcp
->regusers
[j
])
525 if (i
==REGCHANUSERHASHSIZE
) {
526 cs_log(np
, "DELCHAN %s (Cleared chanlev from rollback)", cip
->name
->content
);
527 chanservsendmessage(np
, "Rollback cleared chanlev list, channel deleted.");
532 chanservstdmessage(np
, QM_DONE
);
537 void csdb_retreiveaccounthistory(nick
*np
, reguser
*rup
, int limit
) {
538 pqasyncquery(csdb_doaccounthistory_real
, (void *)np
->numeric
,
539 "SELECT userID, changetime, authtime, oldpassword, newpassword, oldemail, newemail from accounthistory where "
540 "userID=%u order by changetime desc limit %d", rup
->ID
, limit
);
543 void csdb_doaccounthistory_real(PGconn
*dbconn
, void *arg
) {
544 nick
*np
=getnickbynumeric((unsigned int)arg
);
547 char *oldpass
, *newpass
, *oldemail
, *newemail
;
548 time_t changetime
, authtime
;
554 pgres
=PQgetResult(dbconn
);
556 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
557 Error("chanserv", ERR_ERROR
, "Error loading account history data.");
561 if (PQnfields(pgres
) != 7) {
562 Error("chanserv", ERR_ERROR
, "Account history data format error.");
566 num
=PQntuples(pgres
);
573 if (!(rup
=getreguserfromnick(np
)) || !UHasOperPriv(rup
)) {
574 Error("chanserv", ERR_ERROR
, "No reguser pointer or oper privs in account history.");
579 chanservsendmessage(np
, "Number: Time: Old password: New password: Old email: New email:");
580 for (i
=0; i
<num
; i
++) {
581 userID
=strtoul(PQgetvalue(pgres
, i
, 0), NULL
, 10);
582 changetime
=strtoul(PQgetvalue(pgres
, i
, 1), NULL
, 10);
583 authtime
=strtoul(PQgetvalue(pgres
, i
, 2), NULL
, 10);
584 oldpass
=PQgetvalue(pgres
, i
, 3);
585 newpass
=PQgetvalue(pgres
, i
, 4);
586 oldemail
=PQgetvalue(pgres
, i
, 5);
587 newemail
=PQgetvalue(pgres
, i
, 6);
588 tmp
=localtime(&changetime
);
589 strftime(tbuf
, 15, "%d/%m/%y %H:%M", tmp
);
590 chanservsendmessage(np
, "#%-6d %-15s %-14s %-14s %-30s %s", ++count
, tbuf
, oldpass
, newpass
, oldemail
, newemail
);
592 chanservstdmessage(np
, QM_ENDOFLIST
);
597 void csdb_rollbackaccounthistory(nick
*np
, reguser
* rup
, time_t starttime
) {
598 pqasyncquery(csdb_dorollbackaccount_real
, (void *)np
->numeric
,
599 "SELECT userID, changetime, authtime, oldpassword, newpassword, oldemail, newemail from accounthistory where "
600 "userID=%u and changetime>%lu order by changetime desc limit 10", rup
->ID
, starttime
);
603 void csdb_dorollbackaccount_real(PGconn
*dbconn
, void *arg
) {
604 nick
*np
=getnickbynumeric((unsigned int)arg
);
607 char *oldpass
, *newpass
, *oldemail
, *newemail
;
608 time_t changetime
, authtime
;
614 pgres
=PQgetResult(dbconn
);
616 if (PQresultStatus(pgres
) != PGRES_TUPLES_OK
) {
617 Error("chanserv", ERR_ERROR
, "Error loading account rollback data.");
621 if (PQnfields(pgres
) != 7) {
622 Error("chanserv", ERR_ERROR
, "Account rollback data format error.");
626 num
=PQntuples(pgres
);
633 if (!(rup
=getreguserfromnick(np
)) || !UHasOperPriv(rup
)) {
634 Error("chanserv", ERR_ERROR
, "No reguser pointer or oper privs in rollback account.");
639 chanservsendmessage(np
, "Attempting to rollback account %s:", rup
->username
);
640 for (i
=0; i
<num
; i
++) {
641 userID
=strtoul(PQgetvalue(pgres
, i
, 0), NULL
, 10);
642 changetime
=strtoul(PQgetvalue(pgres
, i
, 1), NULL
, 10);
643 authtime
=strtoul(PQgetvalue(pgres
, i
, 2), NULL
, 10);
644 oldpass
=PQgetvalue(pgres
, i
, 3);
645 newpass
=PQgetvalue(pgres
, i
, 4);
646 oldemail
=PQgetvalue(pgres
, i
, 5);
647 newemail
=PQgetvalue(pgres
, i
, 6);
648 if (strlen(newpass
) > 0) {
649 setpassword(rup
, oldpass
);
650 chanservsendmessage(np
, "Restoring old password (%s -> %s)", newpass
, oldpass
);
652 else if (strlen(newemail
) > 0) {
653 freesstring(rup
->email
);
654 rup
->email
=getsstring(oldemail
, EMAILLEN
);
655 rup
->lastemailchange
=changetime
;
656 chanservsendmessage(np
, "Restoring old email (%s -> %s)", newemail
, oldemail
);
659 csdb_updateuser(rup
);
660 chanservstdmessage(np
, QM_DONE
);