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