]> jfr.im git - irc/quakenet/newserv.git/blob - chanserv/database/chanservdb.c
merge
[irc/quakenet/newserv.git] / chanserv / database / chanservdb.c
1 /*
2 * chanservdb.c:
3 * Handles the SQL stuff for the channel service.
4 */
5
6 #include "../chanserv.h"
7 #include "../../pqsql/pqsql.h"
8 #include "../../core/config.h"
9 #include "../../lib/sstring.h"
10 #include "../../parser/parser.h"
11 #include "../../core/events.h"
12 #include "../../core/nsmalloc.h"
13
14 #include <string.h>
15 #include <libpq-fe.h>
16 #include <stdio.h>
17 #include <sys/poll.h>
18 #include <stdarg.h>
19
20 int chanservdb_ready;
21
22 typedef struct tabledesc {
23 sstring *tablename; /* Name of table */
24 PQQueryHandler init; /* Function to be called when transaction opens */
25 PQQueryHandler data; /* Function to be called to load data */
26 PQQueryHandler fini; /* Function to be called to clean up */
27 } tabledesc;
28
29 regchan **allchans;
30
31 int chanservext;
32 int chanservaext;
33
34 unsigned int lastchannelID;
35 unsigned int lastuserID;
36 unsigned int lastbanID;
37 unsigned int lastdomainID;
38
39 /* Local prototypes */
40 void csdb_handlestats(int hooknum, void *arg);
41 void loadmessages_part1(PGconn *, void *);
42 void loadmessages_part2(PGconn *, void *);
43 void loadcommandsummary_real(PGconn *, void *);
44
45 /* Generic loading functions */
46 void loadall(char *, PQQueryHandler, PQQueryHandler, PQQueryHandler);
47 void doloadall(PGconn *, void *);
48
49 /* User loading functions */
50 void loadsomeusers(PGconn *, void *);
51 void loadusersdone(PGconn *, void *);
52
53 /* Channel loading functions */
54 void loadsomechannels(PGconn *, void *);
55 void loadchannelsdone(PGconn *, void *);
56
57 /* Chanuser loading functions */
58 void loadchanusersinit(PGconn *, void *);
59 void loadsomechanusers(PGconn *, void *);
60 void loadchanusersdone(PGconn *, void *);
61
62 /* Chanban loading functions */
63 void loadsomechanbans(PGconn *, void *);
64 void loadchanbansdone(PGconn *, void *);
65
66 /* Mail Domain loading functions */
67 void loadsomemaildomains(PGconn *, void *);
68 void loadmaildomainsdone(PGconn *, void *);
69
70 /* Free sstrings in the structures */
71 void csdb_freestuff();
72
73 static void setuptables() {
74 /* Set up the tables */
75 /* User table */
76 pqcreatequery("CREATE TABLE users ("
77 "ID INT NOT NULL,"
78 "username VARCHAR(16) NOT NULL,"
79 "created INT NOT NULL,"
80 "lastauth INT NOT NULL,"
81 "lastemailchng INT NOT NULL,"
82 "flags INT NOT NULL,"
83 "language INT NOT NULL,"
84 "suspendby INT NOT NULL,"
85 "suspendexp INT NOT NULL,"
86 "password VARCHAR(11) NOT NULL,"
87 "masterpass VARCHAR(11),"
88 "email VARCHAR(100),"
89 "lastuserhost VARCHAR(75),"
90 "suspendreason VARCHAR(250),"
91 "comment VARCHAR(250),"
92 "info VARCHAR(100),"
93 "PRIMARY KEY (ID))");
94
95 pqcreatequery("CREATE INDEX user_username_index ON users (username)");
96
97 /* Channel table */
98 pqcreatequery("CREATE TABLE channels ("
99 "ID INT NOT NULL,"
100 "name VARCHAR(250) NOT NULL,"
101 "flags INT NOT NULL,"
102 "forcemodes INT NOT NULL,"
103 "denymodes INT NOT NULL,"
104 "chanlimit INT NOT NULL,"
105 "autolimit INT NOT NULL,"
106 "banstyle INT NOT NULL,"
107 "created INT NOT NULL,"
108 "lastactive INT NOT NULL,"
109 "statsreset INT NOT NULL,"
110 "banduration INT NOT NULL,"
111 "founder INT NOT NULL,"
112 "addedby INT NOT NULL,"
113 "suspendby INT NOT NULL,"
114 "chantype SMALLINT NOT NULL,"
115 "totaljoins INT NOT NULL,"
116 "tripjoins INT NOT NULL,"
117 "maxusers INT NOT NULL,"
118 "tripusers INT NOT NULL,"
119 "welcome VARCHAR(500),"
120 "topic VARCHAR(250),"
121 "chankey VARCHAR(23),"
122 "suspendreason VARCHAR(250),"
123 "comment VARCHAR(250),"
124 "lasttimestamp INT,"
125 "PRIMARY KEY (ID))");
126
127 /* Chanuser table */
128 pqcreatequery("CREATE TABLE chanusers ("
129 "userID INT NOT NULL,"
130 "channelID INT NOT NULL,"
131 "flags INT NOT NULL,"
132 "changetime INT NOT NULL,"
133 "usetime INT NOT NULL,"
134 "info VARCHAR(100) NOT NULL,"
135 "PRIMARY KEY (userID, channelID))");
136
137 pqcreatequery("CREATE INDEX chanusers_userID_index on chanusers (userID)");
138 pqcreatequery("CREATE INDEX chanusers_channelID_index on chanusers (channelID)");
139
140 pqcreatequery("CREATE TABLE bans ("
141 "banID INT NOT NULL," /* Unique number for the ban to make
142 DELETEs process in finite time.. */
143 "channelID INT NOT NULL,"
144 "userID INT NOT NULL," /* Who set the ban.. */
145 "hostmask VARCHAR(100) NOT NULL," /* needs to be at least USERLEN+NICKLEN+HOSTLEN+2 */
146 "expiry INT NOT NULL,"
147 "reason VARCHAR(200),"
148 "PRIMARY KEY(banID))");
149
150 pqcreatequery("CREATE INDEX bans_channelID_index on bans (channelID)");
151
152 pqcreatequery("CREATE TABLE languages ("
153 "languageID INT NOT NULL,"
154 "code VARCHAR(2) NOT NULL,"
155 "name VARCHAR(30) NOT NULL)");
156
157 pqcreatequery("CREATE TABLE messages ("
158 "languageID INT NOT NULL,"
159 "messageID INT NOT NULL,"
160 "message VARCHAR(250) NOT NULL,"
161 "PRIMARY KEY (languageID, messageID))");
162
163 pqcreatequery("CREATE TABLE help ("
164 "commandID INT NOT NULL,"
165 "command VARCHAR(30) NOT NULL,"
166 "languageID INT NOT NULL,"
167 "summary VARCHAR(200) NOT NULL,"
168 "fullinfo TEXT NOT NULL,"
169 "PRIMARY KEY (commandID, languageID))");
170
171 pqcreatequery("CREATE TABLE email ("
172 "userID INT NOT NULL,"
173 "emailtype INT NOT NULL,"
174 "prevEmail VARCHAR(100),"
175 "mailID VARCHAR(128))");
176
177 pqcreatequery("CREATE TABLE maildomain ("
178 "ID INT NOT NULL,"
179 "name VARCHAR NOT NULL,"
180 "domainlimit INT NOT NULL,"
181 "actlimit INT NOT NULL,"
182 "flags INT NOT NULL,"
183 "PRIMARY KEY (ID))");
184
185 pqcreatequery("CREATE TABLE authhistory ("
186 "userID INT NOT NULL,"
187 "nick VARCHAR(15) NOT NULL,"
188 "username VARCHAR(10) NOT NULL,"
189 "host VARCHAR(63) NOT NULL,"
190 "authtime INT NOT NULL,"
191 "disconnecttime INT NOT NULL,"
192 "PRIMARY KEY (userID, authtime))");
193
194 pqcreatequery("CREATE INDEX authhistory_userID_index on authhistory(userID)");
195 pqcreatequery("CREATE TABLE chanlevhistory ("
196 "userID INT NOT NULL,"
197 "channelID INT NOT NULL,"
198 "targetID INT NOT NULL,"
199 "changetime INT NOT NULL,"
200 "authtime INT NOT NULL,"
201 "oldflags INT NOT NULL,"
202 "newflags INT NOT NULL)");
203
204 pqcreatequery("CREATE INDEX chanlevhistory_userID_index on chanlevhistory(userID)");
205 pqcreatequery("CREATE INDEX chanlevhistory_channelID_index on chanlevhistory(channelID)");
206 pqcreatequery("CREATE INDEX chanlevhistory_targetID_index on chanlevhistory(targetID)");
207
208 pqcreatequery("CREATE TABLE accounthistory ("
209 "userID INT NOT NULL,"
210 "changetime INT NOT NULL,"
211 "authtime INT NOT NULL,"
212 "oldpassword VARCHAR(11),"
213 "newpassword VARCHAR(11),"
214 "oldemail VARCHAR(100),"
215 "newemail VARCHAR(100),"
216 "PRIMARY KEY (userID, changetime))");
217
218 pqcreatequery("CREATE INDEX accounthistory_userID_index on accounthistory(userID)");
219 }
220
221 void _init() {
222 chanservext=registerchanext("chanserv");
223 chanservaext=registerauthnameext("chanserv");
224
225 /* Set up the allocators and hashes */
226 chanservallocinit();
227 chanservhashinit();
228
229 /* And the messages */
230 initmessages();
231
232 if (pqconnected() && (chanservext!=-1) && (chanservaext!=-1)) {
233 registerhook(HOOK_CORE_STATSREQUEST, csdb_handlestats);
234
235 setuptables();
236
237 lastuserID=lastchannelID=lastdomainID=0;
238
239 loadall("users",NULL,loadsomeusers,loadusersdone);
240 loadall("channels",NULL,loadsomechannels,loadchannelsdone);
241 loadall("chanusers",loadchanusersinit,loadsomechanusers,loadchanusersdone);
242 loadall("bans",NULL,loadsomechanbans,loadchanbansdone);
243 loadall("maildomain",NULL, loadsomemaildomains,loadmaildomainsdone);
244
245 loadmessages();
246 }
247 }
248
249 void _fini() {
250 if (chanservext!=-1)
251 releasechanext(chanservext);
252
253 if (chanservaext!=-1)
254 releaseauthnameext(chanservaext);
255
256 csdb_freestuff();
257 nsfreeall(POOL_CHANSERVDB);
258 }
259
260 void csdb_handlestats(int hooknum, void *arg) {
261 /* long level=(long)arg; */
262
263 /* Keeping options open here */
264 }
265
266 void chanservdbclose() {
267
268 deregisterhook(HOOK_CORE_STATSREQUEST, csdb_handlestats);
269
270 }
271
272 /*
273 * loadall():
274 * Generic function to handle load of an entire table..
275 */
276
277 void loadall(char *table, PQQueryHandler init, PQQueryHandler data, PQQueryHandler fini) {
278 tabledesc *thedesc;
279
280 thedesc=malloc(sizeof(tabledesc));
281
282 thedesc->tablename=getsstring(table,100);
283 thedesc->init=init;
284 thedesc->data=data;
285 thedesc->fini=fini;
286
287 pqasyncquery(doloadall, thedesc, "SELECT count(*) FROM %s",thedesc->tablename->content);
288 }
289
290 void doloadall(PGconn *dbconn, void *arg) {
291 PGresult *pgres;
292 int i,count;
293 tabledesc *thedesc=arg;
294
295 pgres=PQgetResult(dbconn);
296
297 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
298 Error("chanserv",ERR_ERROR,"Error getting row count for %s.",thedesc->tablename->content);
299 return;
300 }
301
302 if (PQnfields(pgres)!=1) {
303 Error("chanserv",ERR_ERROR,"Count query format error for %s.",thedesc->tablename->content);
304 return;
305 }
306
307 count=strtoul(PQgetvalue(pgres,0,0),NULL,10);
308
309 PQclear(pgres);
310
311 Error("chanserv",ERR_INFO,"Found %d entries in table %s, scheduling load.",count,
312 thedesc->tablename->content);
313
314 pqasyncquery(thedesc->init, NULL, "BEGIN");
315 pqquery("DECLARE mycurs CURSOR FOR SELECT * from %s",
316 thedesc->tablename->content);
317
318 for (i=0;(count-i)>1000;i+=1000) {
319 pqasyncquery(thedesc->data, NULL, "FETCH 1000 FROM mycurs");
320 }
321
322 pqasyncquery(thedesc->data, NULL, "FETCH ALL FROM mycurs");
323
324 pqquery("CLOSE mycurs");
325 pqasyncquery(thedesc->fini, NULL, "COMMIT");
326
327 /* Free structures.. */
328 freesstring(thedesc->tablename);
329 free(thedesc);
330 }
331
332 /*
333 * loadsomeusers():
334 * Loads some users in from the SQL DB
335 */
336
337 void loadsomeusers(PGconn *dbconn, void *arg) {
338 PGresult *pgres;
339 reguser *rup;
340 unsigned int i,num;
341 char *local;
342
343 pgres=PQgetResult(dbconn);
344
345 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
346 Error("chanserv",ERR_ERROR,"Error loading user DB");
347 return;
348 }
349
350 if (PQnfields(pgres)!=16) {
351 Error("chanserv",ERR_ERROR,"User DB format error");
352 return;
353 }
354
355 num=PQntuples(pgres);
356
357 for(i=0;i<num;i++) {
358 rup=getreguser();
359 rup->status=0;
360 rup->ID=strtoul(PQgetvalue(pgres,i,0),NULL,10);
361 strncpy(rup->username,PQgetvalue(pgres,i,1),NICKLEN); rup->username[NICKLEN]='\0';
362 rup->created=strtoul(PQgetvalue(pgres,i,2),NULL,10);
363 rup->lastauth=strtoul(PQgetvalue(pgres,i,3),NULL,10);
364 rup->lastemailchange=strtoul(PQgetvalue(pgres,i,4),NULL,10);
365 rup->flags=strtoul(PQgetvalue(pgres,i,5),NULL,10);
366 rup->languageid=strtoul(PQgetvalue(pgres,i,6),NULL,10);
367 rup->suspendby=strtoul(PQgetvalue(pgres,i,7),NULL,10);
368 rup->suspendexp=strtoul(PQgetvalue(pgres,i,8),NULL,10);
369 strncpy(rup->password,PQgetvalue(pgres,i,9),PASSLEN); rup->password[PASSLEN]='\0';
370 strncpy(rup->masterpass,PQgetvalue(pgres,i,10),PASSLEN); rup->masterpass[PASSLEN]='\0';
371 rup->email=getsstring(PQgetvalue(pgres,i,11),100);
372 if (rup->email) {
373 rup->domain=findorcreatemaildomain(rup->email->content);
374 addregusertomaildomain(rup, rup->domain);
375
376 char *dupemail = strdup(rup->email->content);
377 if(local=strchr(dupemail, '@')) {
378 *(local++)='\0';
379 rup->localpart=getsstring(local,EMAILLEN);
380 } else {
381 rup->localpart=NULL;
382 }
383 free(dupemail);
384 } else {
385 rup->domain=NULL;
386 rup->localpart=NULL;
387 }
388 rup->lastuserhost=getsstring(PQgetvalue(pgres,i,12),75);
389 rup->suspendreason=getsstring(PQgetvalue(pgres,i,13),250);
390 rup->comment=getsstring(PQgetvalue(pgres,i,14),250);
391 rup->info=getsstring(PQgetvalue(pgres,i,15),100);
392 rup->knownon=NULL;
393 rup->nicks=NULL;
394 rup->checkshd=NULL;
395 rup->stealcount=0;
396 rup->fakeuser=NULL;
397 addregusertohash(rup);
398
399 if (rup->ID > lastuserID) {
400 lastuserID=rup->ID;
401 }
402 }
403
404 PQclear(pgres);
405 }
406
407 void loadusersdone(PGconn *conn, void *arg) {
408 Error("chanserv",ERR_INFO,"Load users done (highest ID was %d)",lastuserID);
409 }
410
411 /*
412 * Channel loading functions
413 */
414
415 void loadsomechannels(PGconn *dbconn, void *arg) {
416 PGresult *pgres;
417 regchan *rcp;
418 int i,num;
419 chanindex *cip;
420 time_t now=time(NULL);
421
422 pgres=PQgetResult(dbconn);
423
424 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
425 Error("chanserv",ERR_ERROR,"Error loading channel DB");
426 return;
427 }
428
429 if (PQnfields(pgres)!=26) {
430 Error("chanserv",ERR_ERROR,"Channel DB format error");
431 return;
432 }
433
434 num=PQntuples(pgres);
435
436 for(i=0;i<num;i++) {
437 cip=findorcreatechanindex(PQgetvalue(pgres,i,1));
438 if (cip->exts[chanservext]) {
439 Error("chanserv",ERR_WARNING,"%s in database twice - this WILL cause problems later.",cip->name->content);
440 continue;
441 }
442 rcp=getregchan();
443 cip->exts[chanservext]=rcp;
444
445 rcp->ID=strtoul(PQgetvalue(pgres,i,0),NULL,10);
446 rcp->index=cip;
447 rcp->flags=strtoul(PQgetvalue(pgres,i,2),NULL,10);
448 rcp->status=0; /* Non-DB field */
449 rcp->lastbancheck=0;
450 rcp->lastcountersync=now;
451 rcp->lastpart=0;
452 rcp->bans=NULL;
453 rcp->forcemodes=strtoul(PQgetvalue(pgres,i,3),NULL,10);
454 rcp->denymodes=strtoul(PQgetvalue(pgres,i,4),NULL,10);
455 rcp->limit=strtoul(PQgetvalue(pgres,i,5),NULL,10);
456 rcp->autolimit=strtoul(PQgetvalue(pgres,i,6),NULL,10);
457 rcp->banstyle=strtoul(PQgetvalue(pgres,i,7),NULL,10);
458 rcp->created=strtoul(PQgetvalue(pgres,i,8),NULL,10);
459 rcp->lastactive=strtoul(PQgetvalue(pgres,i,9),NULL,10);
460 rcp->statsreset=strtoul(PQgetvalue(pgres,i,10),NULL,10);
461 rcp->banduration=strtoul(PQgetvalue(pgres,i,11),NULL,10);
462 rcp->founder=strtol(PQgetvalue(pgres,i,12),NULL,10);
463 rcp->addedby=strtol(PQgetvalue(pgres,i,13),NULL,10);
464 rcp->suspendby=strtol(PQgetvalue(pgres,i,14),NULL,10);
465 rcp->chantype=strtoul(PQgetvalue(pgres,i,15),NULL,10);
466 rcp->totaljoins=strtoul(PQgetvalue(pgres,i,16),NULL,10);
467 rcp->tripjoins=strtoul(PQgetvalue(pgres,i,17),NULL,10);
468 rcp->maxusers=strtoul(PQgetvalue(pgres,i,18),NULL,10);
469 rcp->tripusers=strtoul(PQgetvalue(pgres,i,19),NULL,10);
470 rcp->welcome=getsstring(PQgetvalue(pgres,i,20),500);
471 rcp->topic=getsstring(PQgetvalue(pgres,i,21),TOPICLEN);
472 rcp->key=getsstring(PQgetvalue(pgres,i,22),KEYLEN);
473 rcp->suspendreason=getsstring(PQgetvalue(pgres,i,23),250);
474 rcp->comment=getsstring(PQgetvalue(pgres,i,24),250);
475 rcp->checksched=NULL;
476 rcp->ltimestamp=strtoul(PQgetvalue(pgres,i,25),NULL,10);
477 memset(rcp->regusers,0,REGCHANUSERHASHSIZE*sizeof(reguser *));
478
479 if (rcp->ID > lastchannelID)
480 lastchannelID=rcp->ID;
481
482 if (CIsAutoLimit(rcp))
483 rcp->limit=0;
484 }
485
486 PQclear(pgres);
487 }
488
489 void loadchannelsdone(PGconn *dbconn, void *arg) {
490 Error("chanserv",ERR_INFO,"Channel load done (highest ID was %d)",lastchannelID);
491 }
492
493 void loadchanusersinit(PGconn *dbconn, void *arg) {
494 int i;
495 chanindex *cip;
496 regchan *rcp;
497
498 allchans=(regchan **)malloc((lastchannelID+1)*sizeof(regchan *));
499 memset(allchans,0,(lastchannelID+1)*sizeof(regchan *));
500 for (i=0;i<CHANNELHASHSIZE;i++) {
501 for (cip=chantable[i];cip;cip=cip->next) {
502 if (cip->exts[chanservext]) {
503 rcp=(regchan *)cip->exts[chanservext];
504 allchans[rcp->ID]=rcp;
505 }
506 }
507 }
508 }
509
510 void loadsomechanusers(PGconn *dbconn, void *arg) {
511 PGresult *pgres;
512 regchanuser *rcup;
513 int i,num;
514 regchan *rcp;
515 reguser *rup;
516 authname *anp;
517 int uid,cid;
518 int total=0;
519
520 /* Set up the allchans array */
521 pgres=PQgetResult(dbconn);
522
523 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
524 Error("chanserv",ERR_ERROR,"Error loading chanusers.");
525 return;
526 }
527
528 if (PQnfields(pgres)!=6) {
529 Error("chanserv",ERR_ERROR,"Chanusers format error");
530 return;
531 }
532
533 num=PQntuples(pgres);
534
535 for(i=0;i<num;i++) {
536 uid=strtol(PQgetvalue(pgres,i,0),NULL,10);
537 cid=strtol(PQgetvalue(pgres,i,1),NULL,10);
538
539 if (!(anp=findauthname(uid)) || !(rup=anp->exts[chanservaext])) {
540 Error("chanserv",ERR_WARNING,"Skipping channeluser for unknown user %d",uid);
541 continue;
542 }
543
544 if (cid>lastchannelID || !(rcp=allchans[cid])) {
545 Error("chanserv",ERR_WARNING,"Skipping channeluser for unknown chan %d",cid);
546 continue;
547 }
548
549 if (rup==NULL || rcp==NULL) {
550 Error("chanserv",ERR_ERROR,"Can't add user %s on channel %s",
551 PQgetvalue(pgres,i,0),PQgetvalue(pgres,i,1));
552 } else {
553 rcup=getregchanuser();
554 rcup->user=rup;
555 rcup->chan=rcp;
556 rcup->flags=strtol(PQgetvalue(pgres,i,2),NULL,10);
557 rcup->changetime=strtol(PQgetvalue(pgres,i,3),NULL,10);
558 rcup->usetime=strtol(PQgetvalue(pgres,i,4),NULL,10);
559 rcup->info=getsstring(PQgetvalue(pgres,i,5),100);
560 addregusertochannel(rcup);
561 total++;
562 }
563 }
564
565 PQclear(pgres);
566 }
567
568 void loadchanusersdone(PGconn *dbconn, void *arg) {
569 Error("chanserv",ERR_INFO,"Channel user load done.");
570 }
571
572 void loadsomechanbans(PGconn *dbconn, void *arg) {
573 PGresult *pgres;
574 regban *rbp;
575 int i,num;
576 regchan *rcp;
577 int uid,cid,bid;
578 time_t expiry,now;
579 int total=0;
580
581 pgres=PQgetResult(dbconn);
582
583 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
584 Error("chanserv",ERR_ERROR,"Error loading bans.");
585 return;
586 }
587
588 if (PQnfields(pgres)!=6) {
589 Error("chanserv",ERR_ERROR,"Ban format error");
590 return;
591 }
592
593 num=PQntuples(pgres);
594
595 now=time(NULL);
596
597 for(i=0;i<num;i++) {
598 bid=strtoul(PQgetvalue(pgres,i,0),NULL,10);
599 cid=strtoul(PQgetvalue(pgres,i,1),NULL,10);
600 uid=strtoul(PQgetvalue(pgres,i,2),NULL,10);
601 expiry=strtoul(PQgetvalue(pgres,i,4),NULL,10);
602
603 if (cid>lastchannelID || !(rcp=allchans[cid])) {
604 Error("chanserv",ERR_WARNING,"Skipping ban for unknown chan %d",cid);
605 continue;
606 }
607
608 rbp=getregban();
609 rbp->setby=uid;
610 rbp->ID=bid;
611 rbp->expiry=expiry;
612 rbp->reason=getsstring(PQgetvalue(pgres,i,5),200);
613 rbp->cbp=makeban(PQgetvalue(pgres,i,3));
614 rbp->next=rcp->bans;
615 rcp->bans=rbp;
616
617 total++;
618
619 if (bid>lastbanID)
620 lastbanID=bid;
621 }
622
623 PQclear(pgres);
624 }
625
626 void loadchanbansdone(PGconn *dbconn, void *arg) {
627 free(allchans);
628
629 Error("chanserv",ERR_INFO,"Channel ban load done, highest ID was %d",lastbanID);
630
631 chanservdb_ready=1;
632 triggerhook(HOOK_CHANSERV_DBLOADED, NULL);
633 }
634
635 void loadmessages() {
636 pqasyncquery(loadmessages_part1, NULL, "SELECT * from languages");
637 }
638
639 void loadmessages_part1(PGconn *dbconn, void *arg) {
640 int i,j;
641 PGresult *pgres;
642 int num;
643
644 /* Firstly, clear up any stale messages */
645 for (i=0;i<MAXLANG;i++) {
646 if (cslanguages[i]) {
647 freesstring(cslanguages[i]->name);
648 free(cslanguages[i]);
649 }
650 for (j=0;j<MAXMESSAGES;j++) {
651 if (csmessages[i][j]) {
652 freesstring(csmessages[i][j]);
653 csmessages[i][j]=NULL;
654 }
655 }
656 }
657
658 pgres=PQgetResult(dbconn);
659
660 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
661 Error("chanserv",ERR_ERROR,"Error loading language list.");
662 return;
663 }
664
665 if (PQnfields(pgres)!=3) {
666 Error("chanserv",ERR_ERROR,"Language list format error.");
667 return;
668 }
669
670 num=PQntuples(pgres);
671
672 for (i=0;i<num;i++) {
673 j=strtol(PQgetvalue(pgres,i,0),NULL,10);
674 if (j<MAXLANG && j>=0) {
675 cslanguages[j]=(cslang *)malloc(sizeof(cslang));
676
677 strncpy(cslanguages[j]->code,PQgetvalue(pgres,i,1),2); cslanguages[j]->code[2]='\0';
678 cslanguages[j]->name=getsstring(PQgetvalue(pgres,i,2),30);
679 }
680 }
681
682 PQclear(pgres);
683
684 if (i>MAXLANG)
685 Error("chanserv",ERR_ERROR,"Found too many languages (%d > %d)",i,MAXLANG);
686
687 pqasyncquery(loadmessages_part2, NULL, "SELECT * from messages");
688 }
689
690 void loadmessages_part2(PGconn *dbconn, void *arg) {
691 PGresult *pgres;
692 int i,j,k,num;
693
694 pgres=PQgetResult(dbconn);
695
696 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
697 Error("chanserv",ERR_ERROR,"Error loading message list.");
698 return;
699 }
700
701 if (PQnfields(pgres)!=3) {
702 Error("chanserv",ERR_ERROR,"Message list format error.");
703 return;
704 }
705
706 num=PQntuples(pgres);
707
708 for (i=0;i<num;i++) {
709 k=strtol(PQgetvalue(pgres,i,0),NULL,10);
710 j=strtol(PQgetvalue(pgres,i,1),NULL,10);
711
712 if (k<0 || k >= MAXLANG) {
713 Error("chanserv",ERR_WARNING,"Language ID out of range on message: %d",k);
714 continue;
715 }
716
717 if (j<0 || j >= MAXMESSAGES) {
718 Error("chanserv",ERR_WARNING,"Message ID out of range on message: %d",j);
719 continue;
720 }
721
722 csmessages[k][j]=getsstring(PQgetvalue(pgres,i,2),250);
723 }
724
725 PQclear(pgres);
726 }
727
728 void loadcommandsummary(Command *cmd) {
729 pqasyncquery(loadcommandsummary_real, (void *)cmd,
730 "SELECT languageID,summary from help where lower(command) = lower('%s')",cmd->command->content);
731 }
732
733 void loadcommandsummary_real(PGconn *dbconn, void *arg) {
734 int i,j,num;
735 PGresult *pgres;
736 cmdsummary *cs;
737 Command *cmd=arg;
738
739 /* Clear up old text first */
740 cs=cmd->ext;
741 for (i=0;i<MAXLANG;i++) {
742 if (cs->bylang[i])
743 freesstring(cs->bylang[i]);
744 }
745
746 pgres=PQgetResult(dbconn);
747
748 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
749 Error("chanserv",ERR_ERROR,"Error loading command summary.");
750 return;
751 }
752
753 if (PQnfields(pgres)!=2) {
754 Error("chanserv",ERR_ERROR,"Command summary format error.");
755 return;
756 }
757
758 num=PQntuples(pgres);
759
760 for (i=0;i<num;i++) {
761 j=strtol(PQgetvalue(pgres,i,0),NULL,10);
762 if (j<MAXLANG && j>=0) {
763 cs->bylang[j]=getsstring(PQgetvalue(pgres,i,1),200);
764 }
765 }
766
767 PQclear(pgres);
768 }
769
770 void csdb_freestuff() {
771 int i;
772 chanindex *cip, *ncip;
773 regchan *rcp;
774 reguser *rup;
775 regchanuser *rcup;
776 regban *rbp;
777 maildomain *mdp;
778
779 for (i=0;i<REGUSERHASHSIZE;i++) {
780 for (rup=regusernicktable[i];rup;rup=rup->nextbyname) {
781 freesstring(rup->email);
782 freesstring(rup->lastuserhost);
783 freesstring(rup->suspendreason);
784 freesstring(rup->comment);
785 freesstring(rup->info);
786
787 for (rcup=rup->knownon;rcup;rcup=rcup->nextbyuser)
788 freesstring(rcup->info);
789 }
790 }
791
792 for (i=0;i<CHANNELHASHSIZE;i++) {
793 for (cip=chantable[i];cip;cip=ncip) {
794 ncip=cip->next;
795 if ((rcp=cip->exts[chanservext])) {
796 freesstring(rcp->welcome);
797 freesstring(rcp->topic);
798 freesstring(rcp->key);
799 freesstring(rcp->suspendreason);
800 freesstring(rcp->comment);
801 for (rbp=rcp->bans;rbp;rbp=rbp->next) {
802 freesstring(rbp->reason);
803 freechanban(rbp->cbp);
804 }
805 cip->exts[chanservext]=NULL;
806 releasechanindex(cip);
807 }
808 }
809 }
810
811 for (i=0; i<MAILDOMAINHASHSIZE; i++) {
812 for (mdp=maildomainnametable[i]; mdp; mdp=mdp->nextbyname)
813 freesstring(mdp->name);
814 }
815 }
816
817 void loadsomemaildomains(PGconn *dbconn,void *arg) {
818 PGresult *pgres;
819 maildomain *mdp;
820 unsigned int i,num;
821 char *domain;
822 pgres=PQgetResult(dbconn);
823
824 if (PQresultStatus(pgres) != PGRES_TUPLES_OK) {
825 Error("chanserv",ERR_ERROR,"Error loading maildomain DB");
826 return;
827 }
828
829 if (PQnfields(pgres)!=4) {
830 Error("chanserv",ERR_ERROR,"Mail Domain DB format error");
831 return;
832 }
833 num=PQntuples(pgres);
834 lastdomainID=0;
835
836 for(i=0;i<num;i++) {
837 domain=strdup(PQgetvalue(pgres,i,1));
838 mdp=findorcreatemaildomain(domain); //@@@ LEN
839
840 mdp->ID=strtoul(PQgetvalue(pgres,i,0),NULL,10);
841 mdp->limit=strtoul(PQgetvalue(pgres,i,2),NULL,10);
842 mdp->actlimit=strtoul(PQgetvalue(pgres,i,3),NULL,10);
843 mdp->flags=strtoul(PQgetvalue(pgres,i,4),NULL,10);
844
845 if (mdp->ID > lastdomainID) {
846 lastdomainID=mdp->ID;
847 }
848 }
849
850 PQclear(pgres);
851 }
852
853 void loadmaildomainsdone(PGconn *dbconn, void *arg) {
854 Error("chanserv",ERR_INFO,"Load Mail Domains done (highest ID was %d)",lastdomainID);
855 }
856