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