]>
Commit | Line | Data |
---|---|---|
c86edd1d Q |
1 | /* |
2 | * chanservdb.c: | |
3 | * Handles the SQL stuff for the channel service. | |
4 | */ | |
5 | ||
6 | #include "chanserv.h" | |
7 | #include <libpq-fe.h> | |
8 | #include <string.h> | |
9 | #include "../core/config.h" | |
10 | #include "../lib/sstring.h" | |
11 | #include "../parser/parser.h" | |
12 | #include "../core/events.h" | |
13 | #include <stdio.h> | |
14 | #include <sys/poll.h> | |
15 | #include <stdarg.h> | |
16 | ||
17 | typedef void (*QueryHandler)(void *); | |
18 | ||
19 | typedef struct qquery { | |
20 | char *query; /* Text of query */ | |
21 | QueryHandler handler; /* Handler function */ | |
22 | void *udata; /* Other data associated with query */ | |
23 | struct qquery *next; /* Next (linked list) */ | |
24 | } qquery; | |
25 | ||
26 | struct helpinfo { | |
27 | unsigned int numeric; | |
28 | sstring *commandname; | |
29 | }; | |
30 | ||
31 | typedef struct tabledesc { | |
32 | sstring *tablename; /* Name of table */ | |
33 | QueryHandler init; /* Function to be called when transaction opens */ | |
34 | QueryHandler data; /* Function to be called to load data */ | |
35 | QueryHandler fini; /* Function to be called to clean up */ | |
36 | } tabledesc; | |
37 | ||
38 | qquery *nextquery, *lastquery; | |
39 | ||
40 | PGconn *dbconn; | |
41 | ||
42 | regchan **allchans; | |
43 | reguser **allusers; | |
44 | ||
45 | int sqlconnected; | |
46 | unsigned int lastchannelID; | |
47 | unsigned int lastuserID; | |
48 | unsigned int lastbanID; | |
49 | ||
50 | /* Local prototypes */ | |
51 | void loadallchanbans(void *arg); | |
52 | void csdb_handler(int fd, short revents); | |
53 | void csdb_queuequery(QueryHandler handler, void *udata, char *format, ...); | |
54 | void csdb_handlestats(int hooknum, void *arg); | |
55 | void loadmessages_part1(void *arg); | |
56 | void loadmessages_part2(void *arg); | |
57 | void loadcommandsummary_real(void *arg); | |
58 | void csdb_dohelp_real(void *arg); | |
59 | ||
60 | /* Generic loading functions */ | |
61 | void loadall(char *, QueryHandler, QueryHandler, QueryHandler); | |
62 | void doloadall(void *arg); | |
63 | ||
64 | /* User loading functions */ | |
65 | void loadsomeusers(void *arg); | |
66 | void loadusersdone(void *arg); | |
67 | ||
68 | /* Channel loading functions */ | |
69 | void loadsomechannels(void *arg); | |
70 | void loadchannelsdone(void *arg); | |
71 | ||
72 | /* Chanuser loading functions */ | |
73 | void loadchanusersinit(void *arg); | |
74 | void loadsomechanusers(void *arg); | |
75 | void loadchanusersdone(void *arg); | |
76 | ||
77 | /* Chanban loading functions */ | |
78 | void loadsomechanbans(void *arg); | |
79 | void loadchanbansdone(void *arg); | |
80 | ||
81 | int chanservdbinit() { | |
82 | sstring *dbhost,*dbusername,*dbpassword,*dbdatabase,*dbport; | |
83 | char connectstr[1000]; | |
84 | ||
85 | sqlconnected=0; | |
86 | ||
87 | registerhook(HOOK_CORE_STATSREQUEST, csdb_handlestats); | |
88 | ||
89 | dbhost=getcopyconfigitem("chanserv","dbhost","localhost",HOSTLEN); | |
90 | dbusername=getcopyconfigitem("chanserv","dbusername","chanserv",20); | |
91 | dbpassword=getcopyconfigitem("chanserv","dbpassword","moo",20); | |
92 | dbdatabase=getcopyconfigitem("chanserv","dbdatabase","chanserv",20); | |
93 | dbport=getcopyconfigitem("chanserv","dbport","3306",8); | |
94 | sprintf(connectstr,"dbname=%s user=%s password=%s", | |
95 | /* dbhost->content, dbport->content, */ | |
96 | dbdatabase->content, dbusername->content, dbpassword->content); | |
97 | ||
98 | Error("chanserv",ERR_INFO,"Attempting database connection: %s",connectstr); | |
99 | ||
100 | /* Blocking connect for now.. */ | |
101 | dbconn=PQconnectdb(connectstr); | |
102 | ||
103 | if (!dbconn || (PQstatus(dbconn)!=CONNECTION_OK)) { | |
104 | Error("chanserv",ERR_ERROR,"Unable to connect to database!"); | |
105 | return 1; | |
106 | } | |
107 | ||
108 | freesstring(dbhost); | |
109 | freesstring(dbusername); | |
110 | freesstring(dbpassword); | |
111 | freesstring(dbdatabase); | |
112 | freesstring(dbport); | |
113 | ||
114 | sqlconnected=1; | |
115 | ||
116 | /* Set up the tables */ | |
117 | /* User table */ | |
118 | PQclear(PQexec(dbconn,"CREATE TABLE users (" | |
119 | "ID INT NOT NULL," | |
120 | "username VARCHAR(16) NOT NULL," | |
121 | "created INT NOT NULL," | |
122 | "lastauth INT NOT NULL," | |
123 | "lastemailchng INT NOT NULL," | |
124 | "flags INT NOT NULL," | |
125 | "language INT NOT NULL," | |
126 | "suspendby INT NOT NULL," | |
127 | "suspendexp INT NOT NULL," | |
128 | "password VARCHAR(11) NOT NULL," | |
129 | "masterpass VARCHAR(11)," | |
130 | "email VARCHAR(100)," | |
131 | "lastuserhost VARCHAR(75)," | |
132 | "suspendreason VARCHAR(250)," | |
133 | "comment VARCHAR(250)," | |
134 | "info VARCHAR(100)," | |
135 | "PRIMARY KEY (ID))")); | |
136 | ||
137 | PQclear(PQexec(dbconn,"CREATE INDEX user_username_index ON users (username)")); | |
138 | ||
139 | /* Channel table */ | |
140 | PQclear(PQexec(dbconn,"CREATE TABLE channels (" | |
141 | "ID INT NOT NULL," | |
142 | "name VARCHAR(250) NOT NULL," | |
143 | "flags INT NOT NULL," | |
144 | "forcemodes INT NOT NULL," | |
145 | "denymodes INT NOT NULL," | |
146 | "chanlimit INT NOT NULL," | |
147 | "autolimit INT NOT NULL," | |
148 | "banstyle INT NOT NULL," | |
149 | "created INT NOT NULL," | |
150 | "lastactive INT NOT NULL," | |
151 | "statsreset INT NOT NULL," | |
152 | "banduration INT NOT NULL," | |
153 | "founder INT NOT NULL," | |
154 | "addedby INT NOT NULL," | |
155 | "suspendby INT NOT NULL," | |
156 | "chantype SMALLINT NOT NULL," | |
157 | "totaljoins INT NOT NULL," | |
158 | "tripjoins INT NOT NULL," | |
159 | "maxusers INT NOT NULL," | |
160 | "tripusers INT NOT NULL," | |
161 | "welcome VARCHAR(500)," | |
162 | "topic VARCHAR(250)," | |
163 | "chankey VARCHAR(23)," | |
164 | "suspendreason VARCHAR(250)," | |
165 | "comment VARCHAR(250)," | |
166 | "PRIMARY KEY (ID))")); | |
167 | ||
168 | /* Chanuser table */ | |
169 | PQclear(PQexec(dbconn,"CREATE TABLE chanusers (" | |
170 | "userID INT NOT NULL," | |
171 | "channelID INT NOT NULL," | |
172 | "flags INT NOT NULL," | |
173 | "changetime INT NOT NULL," | |
174 | "usetime INT NOT NULL," | |
175 | "info VARCHAR(100) NOT NULL," | |
176 | "PRIMARY KEY (userID, channelID))")); | |
177 | ||
178 | PQclear(PQexec(dbconn,"CREATE INDEX chanusers_userID_index on chanusers (userID)")); | |
179 | PQclear(PQexec(dbconn,"CREATE INDEX chanusers_channelID_index on chanusers (channelID)")); | |
180 | ||
181 | PQclear(PQexec(dbconn,"CREATE TABLE bans (" | |
182 | "banID INT NOT NULL," /* Unique number for the ban to make | |
183 | DELETEs process in finite time.. */ | |
184 | "channelID INT NOT NULL," | |
185 | "userID INT NOT NULL," /* Who set the ban.. */ | |
186 | "hostmask VARCHAR(100) NOT NULL," /* needs to be at least USERLEN+NICKLEN+HOSTLEN+2 */ | |
187 | "expiry INT NOT NULL," | |
188 | "reason VARCHAR(200)," | |
189 | "PRIMARY KEY(banID))")); | |
190 | ||
191 | PQclear(PQexec(dbconn,"CREATE INDEX bans_channelID_index on bans (channelID)")); | |
192 | ||
193 | PQclear(PQexec(dbconn,"CREATE TABLE languages (" | |
194 | "languageID INT NOT NULL," | |
195 | "code VARCHAR(2) NOT NULL," | |
196 | "name VARCHAR(30) NOT NULL)")); | |
197 | ||
198 | PQclear(PQexec(dbconn,"CREATE TABLE messages (" | |
199 | "languageID INT NOT NULL," | |
200 | "messageID INT NOT NULL," | |
201 | "message VARCHAR(250) NOT NULL," | |
202 | "PRIMARY KEY (languageID, messageID))")); | |
203 | ||
204 | PQclear(PQexec(dbconn,"CREATE TABLE help (" | |
205 | "commandID INT NOT NULL," | |
206 | "command VARCHAR(30) NOT NULL," | |
207 | "languageID INT NOT NULL," | |
208 | "summary VARCHAR(200) NOT NULL," | |
209 | "fullinfo TEXT NOT NULL," | |
210 | "PRIMARY KEY (commandID, languageID))")); | |
211 | ||
212 | PQclear(PQexec(dbconn,"CREATE TABLE email (" | |
213 | "userID INT NOT NULL," | |
214 | "emailtype INT NOT NULL," | |
215 | "prevEmail VARCHAR(100)," | |
216 | "mailID VARCHAR(128))")); | |
217 | ||
218 | PQsetnonblocking(dbconn, 1); | |
219 | ||
220 | registerhandler(PQsocket(dbconn), POLLIN, csdb_handler); | |
221 | ||
222 | lastuserID=lastchannelID=0; | |
223 | ||
224 | loadall("users",NULL,loadsomeusers,loadusersdone); | |
225 | loadall("channels",NULL,loadsomechannels,loadchannelsdone); | |
226 | loadall("chanusers",loadchanusersinit,loadsomechanusers,loadchanusersdone); | |
227 | loadall("bans",NULL,loadsomechanbans,loadchanbansdone); | |
228 | ||
229 | loadmessages(); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | void csdb_handler(int fd, short revents) { | |
235 | PGresult *res; | |
236 | qquery *qqp; | |
237 | ||
238 | if (revents & POLLIN) { | |
239 | PQconsumeInput(dbconn); | |
240 | ||
241 | if (!PQisBusy(dbconn)) { | |
242 | /* Query is complete */ | |
243 | if (nextquery->handler) | |
244 | (nextquery->handler)(nextquery->udata); | |
245 | ||
246 | while ((res=PQgetResult(dbconn))) { | |
247 | switch (PQresultStatus(res)) { | |
248 | case PGRES_TUPLES_OK: | |
249 | Error("chanserv",ERR_WARNING,"Unhandled tuples output (query=%s)",nextquery->query); | |
250 | break; | |
251 | ||
252 | case PGRES_NONFATAL_ERROR: | |
253 | case PGRES_FATAL_ERROR: | |
254 | Error("chanserv",ERR_WARNING,"Unhandled error response (query=%s)",nextquery->query); | |
255 | break; | |
256 | ||
257 | default: | |
258 | break; | |
259 | } | |
260 | ||
261 | PQclear(res); | |
262 | } | |
263 | ||
264 | /* Free the query and advance */ | |
265 | qqp=nextquery; | |
266 | if (nextquery==lastquery) { | |
267 | lastquery=NULL; | |
268 | } | |
269 | nextquery=nextquery->next; | |
270 | free(qqp->query); | |
271 | free(qqp); | |
272 | ||
273 | if (nextquery) { | |
274 | /* Submit the next query */ | |
275 | PQsendQuery(dbconn, nextquery->query); | |
276 | PQflush(dbconn); | |
277 | } | |
278 | } | |
279 | } | |
280 | } | |
281 | ||
282 | void csdb_queuequery(QueryHandler handler, void *udata, char *format, ...) { | |
283 | char querybuf[8192]; | |
284 | va_list va; | |
285 | int len; | |
286 | qquery *qp; | |
287 | ||
288 | va_start(va, format); | |
289 | len=vsnprintf(querybuf, 8191, format, va); | |
290 | va_end(va); | |
291 | ||
292 | qp=(qquery *)malloc(sizeof(qquery)); | |
293 | qp->query=malloc(len+1); | |
294 | ||
295 | strcpy(qp->query, querybuf); | |
296 | qp->udata=udata; | |
297 | qp->handler=handler; | |
298 | qp->next=NULL; | |
299 | ||
300 | if (lastquery) { | |
301 | lastquery->next=qp; | |
302 | lastquery=qp; | |
303 | } else { | |
304 | lastquery=nextquery=qp; | |
305 | PQsendQuery(dbconn, nextquery->query); | |
306 | PQflush(dbconn); | |
307 | } | |
308 | } | |
309 | ||
310 | void csdb_handlestats(int hooknum, void *arg) { | |
311 | int level=(int)arg; | |
312 | int i=0; | |
313 | qquery *qqp; | |
314 | char message[100]; | |
315 | ||
316 | if (level>10) { | |
317 | if (nextquery) | |
318 | for (qqp=nextquery;qqp;qqp=qqp->next) | |
319 | i++; | |
320 | ||
321 | sprintf(message,"ChanServ: %6d database queries queued.",i); | |
322 | ||
323 | triggerhook(HOOK_CORE_STATSREPLY, message); | |
324 | } | |
325 | } | |
326 | ||
327 | void chanservdbclose() { | |
328 | qquery *qqp, *nqqp; | |
329 | ||
330 | if (sqlconnected) { | |
331 | deregisterhandler(PQsocket(dbconn), 0); | |
332 | } | |
333 | ||
334 | /* Throw all the queued queries away.. */ | |
335 | for (qqp=nextquery;qqp;qqp=nqqp) { | |
336 | nqqp=qqp->next; | |
337 | if (qqp->handler == csdb_dohelp_real) { | |
338 | free(qqp->udata); | |
339 | } | |
340 | free(qqp->query); | |
341 | free(qqp); | |
342 | } | |
343 | ||
344 | deregisterhook(HOOK_CORE_STATSREQUEST, csdb_handlestats); | |
345 | PQfinish(dbconn); | |
346 | } | |
347 | ||
348 | /* | |
349 | * loadall(): | |
350 | * Generic function to handle load of an entire table.. | |
351 | */ | |
352 | ||
353 | void loadall(char *table, QueryHandler init, QueryHandler data, QueryHandler fini) { | |
354 | tabledesc *thedesc; | |
355 | ||
356 | thedesc=malloc(sizeof(tabledesc)); | |
357 | ||
358 | thedesc->tablename=getsstring(table,100); | |
359 | thedesc->init=init; | |
360 | thedesc->data=data; | |
361 | thedesc->fini=fini; | |
362 | ||
363 | csdb_queuequery(doloadall, thedesc, "SELECT count(*) FROM %s",thedesc->tablename->content); | |
364 | } | |
365 | ||
366 | void doloadall(void *arg) { | |
367 | PGresult *pgres; | |
368 | int i,count; | |
369 | tabledesc *thedesc=arg; | |
370 | ||
371 | pgres=PQgetResult(dbconn); | |
372 | ||
373 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
374 | Error("chanserv",ERR_ERROR,"Error getting row count for %s.",thedesc->tablename->content); | |
375 | return; | |
376 | } | |
377 | ||
378 | if (PQnfields(pgres)!=1) { | |
379 | Error("chanserv",ERR_ERROR,"Count query format error for %s.",thedesc->tablename->content); | |
380 | return; | |
381 | } | |
382 | ||
383 | count=strtoul(PQgetvalue(pgres,0,0),NULL,10); | |
384 | ||
385 | PQclear(pgres); | |
386 | ||
387 | Error("chanserv",ERR_INFO,"Found %d entries in table %s, scheduling load.",count, | |
388 | thedesc->tablename->content); | |
389 | ||
390 | csdb_queuequery(thedesc->init, NULL, "BEGIN"); | |
391 | csdb_queuequery(NULL, NULL, "DECLARE mycurs CURSOR FOR SELECT * from %s", | |
392 | thedesc->tablename->content); | |
393 | ||
394 | for (i=0;(count-i)>1000;i+=1000) { | |
395 | csdb_queuequery(thedesc->data, NULL, "FETCH 1000 FROM mycurs"); | |
396 | } | |
397 | ||
398 | csdb_queuequery(thedesc->data, NULL, "FETCH ALL FROM mycurs"); | |
399 | ||
400 | csdb_queuequery(NULL, NULL, "CLOSE mycurs"); | |
401 | csdb_queuequery(thedesc->fini, NULL, "COMMIT"); | |
402 | ||
403 | /* Free structures.. */ | |
404 | freesstring(thedesc->tablename); | |
405 | free(thedesc); | |
406 | } | |
407 | ||
408 | /* | |
409 | * loadsomeusers(): | |
410 | * Loads some users in from the SQL DB | |
411 | */ | |
412 | ||
413 | void loadsomeusers(void *arg) { | |
414 | PGresult *pgres; | |
415 | reguser *rup; | |
416 | unsigned int i,num; | |
417 | ||
418 | pgres=PQgetResult(dbconn); | |
419 | ||
420 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
421 | Error("chanserv",ERR_ERROR,"Error loading user DB"); | |
422 | return; | |
423 | } | |
424 | ||
425 | if (PQnfields(pgres)!=16) { | |
426 | Error("chanserv",ERR_ERROR,"User DB format error"); | |
427 | return; | |
428 | } | |
429 | ||
430 | num=PQntuples(pgres); | |
431 | ||
432 | lastuserID=0; | |
433 | ||
434 | for(i=0;i<num;i++) { | |
435 | rup=getreguser(); | |
436 | rup->status=0; | |
437 | rup->ID=strtoul(PQgetvalue(pgres,i,0),NULL,10); | |
438 | strncpy(rup->username,PQgetvalue(pgres,i,1),NICKLEN); rup->username[NICKLEN]='\0'; | |
439 | rup->created=strtoul(PQgetvalue(pgres,i,2),NULL,10); | |
440 | rup->lastauth=strtoul(PQgetvalue(pgres,i,3),NULL,10); | |
441 | rup->lastemailchange=strtoul(PQgetvalue(pgres,i,4),NULL,10); | |
442 | rup->flags=strtoul(PQgetvalue(pgres,i,5),NULL,10); | |
443 | rup->languageid=strtoul(PQgetvalue(pgres,i,6),NULL,10); | |
444 | rup->suspendby=strtoul(PQgetvalue(pgres,i,7),NULL,10); | |
445 | rup->suspendexp=strtoul(PQgetvalue(pgres,i,8),NULL,10); | |
446 | strncpy(rup->password,PQgetvalue(pgres,i,9),PASSLEN); rup->password[PASSLEN]='\0'; | |
447 | strncpy(rup->masterpass,PQgetvalue(pgres,i,10),PASSLEN); rup->masterpass[PASSLEN]='\0'; | |
448 | rup->email=getsstring(PQgetvalue(pgres,i,11),100); | |
449 | rup->lastuserhost=getsstring(PQgetvalue(pgres,i,12),75); | |
450 | rup->suspendreason=getsstring(PQgetvalue(pgres,i,13),250); | |
451 | rup->comment=getsstring(PQgetvalue(pgres,i,14),250); | |
452 | rup->info=getsstring(PQgetvalue(pgres,i,15),100); | |
453 | rup->knownon=NULL; | |
454 | rup->nicks=NULL; | |
455 | rup->checkshd=NULL; | |
456 | rup->stealcount=0; | |
457 | rup->fakeuser=NULL; | |
458 | addregusertohash(rup); | |
459 | ||
460 | if (rup->ID > lastuserID) { | |
461 | lastuserID=rup->ID; | |
462 | } | |
463 | } | |
464 | ||
465 | PQclear(pgres); | |
466 | } | |
467 | ||
468 | void loadusersdone(void *arg) { | |
469 | Error("chanserv",ERR_INFO,"Load users done (highest ID was %d)",lastuserID); | |
470 | } | |
471 | ||
472 | /* | |
473 | * Channel loading functions | |
474 | */ | |
475 | ||
476 | void loadsomechannels(void *arg) { | |
477 | PGresult *pgres; | |
478 | regchan *rcp; | |
479 | int i,num; | |
480 | chanindex *cip; | |
481 | time_t now=time(NULL); | |
482 | ||
483 | pgres=PQgetResult(dbconn); | |
484 | ||
485 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
486 | Error("chanserv",ERR_ERROR,"Error loading channel DB"); | |
487 | return; | |
488 | } | |
489 | ||
490 | if (PQnfields(pgres)!=25) { | |
491 | Error("chanserv",ERR_ERROR,"Channel DB format error"); | |
492 | return; | |
493 | } | |
494 | ||
495 | num=PQntuples(pgres); | |
496 | ||
497 | for(i=0;i<num;i++) { | |
498 | cip=findorcreatechanindex(PQgetvalue(pgres,i,1)); | |
499 | if (cip->exts[chanservext]) { | |
500 | Error("chanserv",ERR_WARNING,"%s in database twice - this WILL cause problems later.",cip->name->content); | |
501 | continue; | |
502 | } | |
503 | rcp=getregchan(); | |
504 | cip->exts[chanservext]=rcp; | |
505 | ||
506 | rcp->ID=strtoul(PQgetvalue(pgres,i,0),NULL,10); | |
507 | rcp->index=cip; | |
508 | rcp->flags=strtoul(PQgetvalue(pgres,i,2),NULL,10); | |
509 | rcp->status=0; /* Non-DB field */ | |
510 | rcp->lastbancheck=0; | |
511 | rcp->lastcountersync=now; | |
512 | rcp->lastpart=0; | |
513 | rcp->bans=NULL; | |
514 | rcp->forcemodes=strtoul(PQgetvalue(pgres,i,3),NULL,10); | |
515 | rcp->denymodes=strtoul(PQgetvalue(pgres,i,4),NULL,10); | |
516 | rcp->limit=strtoul(PQgetvalue(pgres,i,5),NULL,10); | |
517 | rcp->autolimit=strtoul(PQgetvalue(pgres,i,6),NULL,10); | |
518 | rcp->banstyle=strtoul(PQgetvalue(pgres,i,7),NULL,10); | |
519 | rcp->created=strtoul(PQgetvalue(pgres,i,8),NULL,10); | |
520 | rcp->lastactive=strtoul(PQgetvalue(pgres,i,9),NULL,10); | |
521 | rcp->statsreset=strtoul(PQgetvalue(pgres,i,10),NULL,10); | |
522 | rcp->banduration=strtoul(PQgetvalue(pgres,i,11),NULL,10); | |
523 | rcp->founder=strtol(PQgetvalue(pgres,i,12),NULL,10); | |
524 | rcp->addedby=strtol(PQgetvalue(pgres,i,13),NULL,10); | |
525 | rcp->suspendby=strtol(PQgetvalue(pgres,i,14),NULL,10); | |
526 | rcp->chantype=strtoul(PQgetvalue(pgres,i,15),NULL,10); | |
527 | rcp->totaljoins=strtoul(PQgetvalue(pgres,i,16),NULL,10); | |
528 | rcp->tripjoins=strtoul(PQgetvalue(pgres,i,17),NULL,10); | |
529 | rcp->maxusers=strtoul(PQgetvalue(pgres,i,18),NULL,10); | |
530 | rcp->tripusers=strtoul(PQgetvalue(pgres,i,19),NULL,10); | |
531 | rcp->welcome=getsstring(PQgetvalue(pgres,i,20),500); | |
532 | rcp->topic=getsstring(PQgetvalue(pgres,i,21),TOPICLEN); | |
533 | rcp->key=getsstring(PQgetvalue(pgres,i,22),KEYLEN); | |
534 | rcp->suspendreason=getsstring(PQgetvalue(pgres,i,23),250); | |
535 | rcp->comment=getsstring(PQgetvalue(pgres,i,24),250); | |
536 | rcp->checksched=NULL; | |
537 | memset(rcp->regusers,0,REGCHANUSERHASHSIZE*sizeof(reguser *)); | |
538 | ||
539 | if (rcp->ID > lastchannelID) | |
540 | lastchannelID=rcp->ID; | |
541 | ||
542 | if (CIsAutoLimit(rcp)) | |
543 | rcp->limit=0; | |
544 | } | |
545 | ||
546 | PQclear(pgres); | |
547 | } | |
548 | ||
549 | void loadchannelsdone(void *arg) { | |
550 | Error("chanserv",ERR_INFO,"Channel load done (highest ID was %d)",lastchannelID); | |
551 | } | |
552 | ||
553 | void loadchanusersinit(void *arg) { | |
554 | int i; | |
555 | chanindex *cip; | |
556 | reguser *rup; | |
557 | regchan *rcp; | |
558 | ||
559 | allchans=(regchan **)malloc((lastchannelID+1)*sizeof(regchan *)); | |
560 | memset(allchans,0,(lastchannelID+1)*sizeof(regchan *)); | |
561 | for (i=0;i<CHANNELHASHSIZE;i++) { | |
562 | for (cip=chantable[i];cip;cip=cip->next) { | |
563 | if (cip->exts[chanservext]) { | |
564 | rcp=(regchan *)cip->exts[chanservext]; | |
565 | allchans[rcp->ID]=rcp; | |
566 | } | |
567 | } | |
568 | } | |
569 | ||
570 | allusers=(reguser **)malloc((lastuserID+1)*sizeof(reguser *)); | |
571 | memset(allusers,0,(lastuserID+1)*sizeof(reguser *)); | |
572 | for (i=0;i<REGUSERHASHSIZE;i++) { | |
573 | for (rup=regusernicktable[i];rup;rup=rup->nextbyname) { | |
574 | allusers[rup->ID]=rup; | |
575 | } | |
576 | } | |
577 | } | |
578 | ||
579 | void loadsomechanusers(void *arg) { | |
580 | PGresult *pgres; | |
581 | regchanuser *rcup; | |
582 | int i,num; | |
583 | regchan *rcp; | |
584 | reguser *rup; | |
585 | int uid,cid; | |
586 | int total=0; | |
587 | ||
588 | /* Set up the allchans and allusers arrays */ | |
589 | pgres=PQgetResult(dbconn); | |
590 | ||
591 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
592 | Error("chanserv",ERR_ERROR,"Error loading chanusers."); | |
593 | return; | |
594 | } | |
595 | ||
596 | if (PQnfields(pgres)!=6) { | |
597 | Error("chanserv",ERR_ERROR,"Chanusers format error"); | |
598 | return; | |
599 | } | |
600 | ||
601 | num=PQntuples(pgres); | |
602 | ||
603 | for(i=0;i<num;i++) { | |
604 | uid=strtol(PQgetvalue(pgres,i,0),NULL,10); | |
605 | cid=strtol(PQgetvalue(pgres,i,1),NULL,10); | |
606 | ||
607 | if (uid>lastuserID || !(rup=allusers[uid])) { | |
608 | Error("chanserv",ERR_WARNING,"Skipping channeluser for unknown user %d",uid); | |
609 | continue; | |
610 | } | |
611 | ||
612 | if (cid>lastchannelID || !(rcp=allchans[cid])) { | |
613 | Error("chanserv",ERR_WARNING,"Skipping channeluser for unknown chan %d",cid); | |
614 | continue; | |
615 | } | |
616 | ||
617 | if (rup==NULL || rcp==NULL) { | |
618 | Error("chanserv",ERR_ERROR,"Can't add user %s on channel %s", | |
619 | PQgetvalue(pgres,i,0),PQgetvalue(pgres,i,1)); | |
620 | } else { | |
621 | rcup=getregchanuser(); | |
622 | rcup->user=rup; | |
623 | rcup->chan=rcp; | |
624 | rcup->flags=strtol(PQgetvalue(pgres,i,2),NULL,10); | |
625 | rcup->changetime=strtol(PQgetvalue(pgres,i,3),NULL,10); | |
626 | rcup->usetime=strtol(PQgetvalue(pgres,i,4),NULL,10); | |
627 | rcup->info=getsstring(PQgetvalue(pgres,i,5),100); | |
628 | addregusertochannel(rcup); | |
629 | total++; | |
630 | } | |
631 | } | |
632 | ||
633 | PQclear(pgres); | |
634 | } | |
635 | ||
636 | void loadchanusersdone(void *arg) { | |
637 | Error("chanserv",ERR_INFO,"Channel user load done."); | |
638 | } | |
639 | ||
640 | void loadsomechanbans(void *arg) { | |
641 | PGresult *pgres; | |
642 | regban *rbp; | |
643 | int i,num; | |
644 | regchan *rcp; | |
645 | int uid,cid,bid; | |
646 | time_t expiry,now; | |
647 | int total=0; | |
648 | ||
649 | pgres=PQgetResult(dbconn); | |
650 | ||
651 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
652 | Error("chanserv",ERR_ERROR,"Error loading bans."); | |
653 | return; | |
654 | } | |
655 | ||
656 | if (PQnfields(pgres)!=6) { | |
657 | Error("chanserv",ERR_ERROR,"Ban format error"); | |
658 | return; | |
659 | } | |
660 | ||
661 | num=PQntuples(pgres); | |
662 | ||
663 | now=time(NULL); | |
664 | ||
665 | for(i=0;i<num;i++) { | |
666 | bid=strtoul(PQgetvalue(pgres,i,0),NULL,10); | |
667 | cid=strtoul(PQgetvalue(pgres,i,1),NULL,10); | |
668 | uid=strtoul(PQgetvalue(pgres,i,2),NULL,10); | |
669 | expiry=strtoul(PQgetvalue(pgres,i,4),NULL,10); | |
670 | ||
671 | if (cid>lastchannelID || !(rcp=allchans[cid])) { | |
672 | Error("chanserv",ERR_WARNING,"Skipping ban for unknown chan %d",cid); | |
673 | continue; | |
674 | } | |
675 | ||
676 | rbp=getregban(); | |
677 | rbp->setby=uid; | |
678 | rbp->ID=bid; | |
679 | rbp->expiry=expiry; | |
680 | rbp->reason=getsstring(PQgetvalue(pgres,i,5),200); | |
681 | rbp->cbp=makeban(PQgetvalue(pgres,i,3)); | |
682 | rbp->next=rcp->bans; | |
683 | rcp->bans=rbp; | |
684 | ||
685 | total++; | |
686 | ||
687 | if (bid>lastbanID) | |
688 | lastbanID=bid; | |
689 | } | |
690 | ||
691 | PQclear(pgres); | |
692 | } | |
693 | ||
694 | void loadchanbansdone(void *arg) { | |
695 | free(allusers); | |
696 | free(allchans); | |
697 | ||
698 | Error("chanserv",ERR_INFO,"Channel ban load done."); | |
699 | ||
700 | triggerhook(HOOK_CHANSERV_DBLOADED, NULL); | |
701 | } | |
702 | ||
703 | void loadmessages() { | |
704 | csdb_queuequery(loadmessages_part1, NULL, "SELECT * from languages"); | |
705 | } | |
706 | ||
707 | void loadmessages_part1(void *arg) { | |
708 | int i,j; | |
709 | PGresult *pgres; | |
710 | int num; | |
711 | ||
712 | /* Firstly, clear up any stale messages */ | |
713 | for (i=0;i<MAXLANG;i++) { | |
714 | if (cslanguages[i]) { | |
715 | freesstring(cslanguages[i]->name); | |
716 | free(cslanguages[i]); | |
717 | } | |
718 | for (j=0;j<MAXMESSAGES;j++) { | |
719 | if (csmessages[i][j]) { | |
720 | freesstring(csmessages[i][j]); | |
721 | csmessages[i][j]=NULL; | |
722 | } | |
723 | } | |
724 | } | |
725 | ||
726 | pgres=PQgetResult(dbconn); | |
727 | ||
728 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
729 | Error("chanserv",ERR_ERROR,"Error loading language list."); | |
730 | return; | |
731 | } | |
732 | ||
733 | if (PQnfields(pgres)!=3) { | |
734 | Error("chanserv",ERR_ERROR,"Language list format error."); | |
735 | return; | |
736 | } | |
737 | ||
738 | num=PQntuples(pgres); | |
739 | ||
740 | for (i=0;i<num;i++) { | |
741 | j=strtol(PQgetvalue(pgres,i,0),NULL,10); | |
742 | if (j<MAXLANG && j>=0) { | |
743 | cslanguages[j]=(cslang *)malloc(sizeof(cslang)); | |
744 | ||
745 | strncpy(cslanguages[j]->code,PQgetvalue(pgres,i,1),2); cslanguages[j]->code[2]='\0'; | |
746 | cslanguages[j]->name=getsstring(PQgetvalue(pgres,i,2),30); | |
747 | } | |
748 | } | |
749 | ||
750 | PQclear(pgres); | |
751 | ||
752 | if (i>MAXLANG) | |
753 | Error("chanserv",ERR_ERROR,"Found too many languages (%d > %d)",i,MAXLANG); | |
754 | ||
755 | csdb_queuequery(loadmessages_part2, NULL, "SELECT * from messages"); | |
756 | } | |
757 | ||
758 | void loadmessages_part2(void *arg) { | |
759 | PGresult *pgres; | |
760 | int i,j,k,num; | |
761 | ||
762 | pgres=PQgetResult(dbconn); | |
763 | ||
764 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
765 | Error("chanserv",ERR_ERROR,"Error loading message list."); | |
766 | return; | |
767 | } | |
768 | ||
769 | if (PQnfields(pgres)!=3) { | |
770 | Error("chanserv",ERR_ERROR,"Message list format error."); | |
771 | return; | |
772 | } | |
773 | ||
774 | num=PQntuples(pgres); | |
775 | ||
776 | for (i=0;i<num;i++) { | |
777 | k=strtol(PQgetvalue(pgres,i,0),NULL,10); | |
778 | j=strtol(PQgetvalue(pgres,i,1),NULL,10); | |
779 | ||
780 | if (k<0 || k >= MAXLANG) { | |
781 | Error("chanserv",ERR_WARNING,"Language ID out of range on message: %d",k); | |
782 | continue; | |
783 | } | |
784 | ||
785 | if (j<0 || j >= MAXMESSAGES) { | |
786 | Error("chanserv",ERR_WARNING,"Message ID out of range on message: %d",j); | |
787 | continue; | |
788 | } | |
789 | ||
790 | csmessages[k][j]=getsstring(PQgetvalue(pgres,i,2),250); | |
791 | } | |
792 | ||
793 | PQclear(pgres); | |
794 | } | |
795 | ||
796 | void loadcommandsummary(Command *cmd) { | |
797 | csdb_queuequery(loadcommandsummary_real, (void *)cmd, | |
798 | "SELECT languageID,summary from help where lower(command) = lower('%s')",cmd->command->content); | |
799 | } | |
800 | ||
801 | void loadcommandsummary_real(void *arg) { | |
802 | int i,j,num; | |
803 | PGresult *pgres; | |
804 | cmdsummary *cs; | |
805 | Command *cmd=arg; | |
806 | ||
807 | /* Clear up old text first */ | |
808 | cs=cmd->ext; | |
809 | for (i=0;i<MAXLANG;i++) { | |
810 | if (cs->bylang[i]) | |
811 | freesstring(cs->bylang[i]); | |
812 | } | |
813 | ||
814 | pgres=PQgetResult(dbconn); | |
815 | ||
816 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
817 | Error("chanserv",ERR_ERROR,"Error loading command summary."); | |
818 | return; | |
819 | } | |
820 | ||
821 | if (PQnfields(pgres)!=2) { | |
822 | Error("chanserv",ERR_ERROR,"Command summary format error."); | |
823 | return; | |
824 | } | |
825 | ||
826 | num=PQntuples(pgres); | |
827 | ||
828 | for (i=0;i<num;i++) { | |
829 | j=strtol(PQgetvalue(pgres,i,0),NULL,10); | |
830 | if (j<MAXLANG && j>=0) { | |
831 | cs->bylang[j]=getsstring(PQgetvalue(pgres,i,1),200); | |
832 | } | |
833 | } | |
834 | ||
835 | PQclear(pgres); | |
836 | } | |
837 | ||
838 | void csdb_updateauthinfo(reguser *rup) { | |
839 | char eschost[150]; | |
840 | ||
841 | PQescapeString(eschost,rup->lastuserhost->content,rup->lastuserhost->length); | |
842 | csdb_queuequery(NULL, NULL, "UPDATE users SET lastauth=%lu,lastuserhost='%s' WHERE ID=%u", | |
843 | rup->lastauth,eschost,rup->ID); | |
844 | } | |
845 | ||
846 | void csdb_updatelastjoin(regchanuser *rcup) { | |
847 | csdb_queuequery(NULL, NULL, "UPDATE chanusers SET usetime=%lu WHERE userID=%u and channelID=%u", | |
848 | rcup->usetime, rcup->user->ID, rcup->chan->ID); | |
849 | } | |
850 | ||
851 | void csdb_updatetopic(regchan *rcp) { | |
852 | char esctopic[TOPICLEN*2+5]; | |
853 | ||
854 | if (rcp->topic) { | |
855 | PQescapeString(esctopic,rcp->topic->content,rcp->topic->length); | |
856 | } else { | |
857 | esctopic[0]='\0'; | |
858 | } | |
859 | csdb_queuequery(NULL, NULL, "UPDATE channels SET topic='%s' WHERE ID=%u",esctopic,rcp->ID); | |
860 | } | |
861 | ||
862 | void csdb_updatechannel(regchan *rcp) { | |
863 | char escwelcome[510]; | |
864 | char esctopic[510]; | |
865 | char esckey[70]; | |
866 | char escreason[510]; | |
867 | char esccomment[510]; | |
868 | char escname[1000]; | |
869 | ||
870 | PQescapeString(escname, rcp->index->name->content, rcp->index->name->length); | |
871 | ||
872 | if (rcp->welcome) | |
873 | PQescapeString(escwelcome, rcp->welcome->content, | |
874 | rcp->welcome->length); | |
875 | else | |
876 | escwelcome[0]='\0'; | |
877 | ||
878 | if (rcp->topic) | |
879 | PQescapeString(esctopic, rcp->topic->content, rcp->topic->length); | |
880 | else | |
881 | esctopic[0]='\0'; | |
882 | ||
883 | if (rcp->key) | |
884 | PQescapeString(esckey, rcp->key->content, rcp->key->length); | |
885 | else | |
886 | esckey[0]='\0'; | |
887 | ||
888 | if (rcp->suspendreason) | |
889 | PQescapeString(escreason, rcp->suspendreason->content, | |
890 | rcp->suspendreason->length); | |
891 | else | |
892 | escreason[0]='\0'; | |
893 | ||
894 | if (rcp->comment) | |
895 | PQescapeString(esccomment, rcp->comment->content, | |
896 | rcp->comment->length); | |
897 | else | |
898 | esccomment[0]='\0'; | |
899 | ||
900 | csdb_queuequery(NULL, NULL, "UPDATE channels SET name='%s', flags=%d, forcemodes=%d," | |
901 | "denymodes=%d, chanlimit=%d, autolimit=%d, banstyle=%d," | |
902 | "lastactive=%lu,statsreset=%lu, banduration=%lu, founder=%u," | |
903 | "addedby=%u, suspendby=%u, chantype=%d, totaljoins=%u," | |
904 | "tripjoins=%u, maxusers=%u, tripusers=%u," | |
905 | "welcome='%s', topic='%s', chankey='%s', suspendreason='%s'," | |
906 | "comment='%s' WHERE ID=%u",escname,rcp->flags,rcp->forcemodes, | |
907 | rcp->denymodes,rcp->limit,rcp->autolimit, rcp->banstyle, | |
908 | rcp->lastactive,rcp->statsreset,rcp->banduration, | |
909 | rcp->founder, rcp->addedby, rcp->suspendby, | |
910 | rcp->chantype,rcp->totaljoins,rcp->tripjoins, | |
911 | rcp->maxusers,rcp->tripusers, | |
912 | escwelcome,esctopic,esckey,escreason,esccomment,rcp->ID); | |
913 | } | |
914 | ||
915 | void csdb_updatechannelcounters(regchan *rcp) { | |
916 | csdb_queuequery(NULL, NULL, "UPDATE channels SET " | |
917 | "lastactive=%lu, totaljoins=%u," | |
918 | "tripjoins=%u, maxusers=%u, tripusers=%u " | |
919 | "WHERE ID=%u", | |
920 | rcp->lastactive, | |
921 | rcp->totaljoins,rcp->tripjoins, | |
922 | rcp->maxusers,rcp->tripusers, | |
923 | rcp->ID); | |
924 | } | |
925 | ||
926 | void csdb_createchannel(regchan *rcp) { | |
927 | char escwelcome[510]; | |
928 | char esctopic[510]; | |
929 | char esckey[70]; | |
930 | char escreason[510]; | |
931 | char esccomment[510]; | |
932 | char escname[510]; | |
933 | ||
934 | PQescapeString(escname, rcp->index->name->content, rcp->index->name->length); | |
935 | ||
936 | if (rcp->welcome) | |
937 | PQescapeString(escwelcome, rcp->welcome->content, | |
938 | rcp->welcome->length); | |
939 | else | |
940 | escwelcome[0]='\0'; | |
941 | ||
942 | if (rcp->topic) | |
943 | PQescapeString(esctopic, rcp->topic->content, rcp->topic->length); | |
944 | else | |
945 | esctopic[0]='\0'; | |
946 | ||
947 | if (rcp->key) | |
948 | PQescapeString(esckey, rcp->key->content, rcp->key->length); | |
949 | else | |
950 | esckey[0]='\0'; | |
951 | ||
952 | if (rcp->suspendreason) | |
953 | PQescapeString(escreason, rcp->suspendreason->content, | |
954 | rcp->suspendreason->length); | |
955 | else | |
956 | escreason[0]='\0'; | |
957 | ||
958 | if (rcp->comment) | |
959 | PQescapeString(esccomment, rcp->comment->content, | |
960 | rcp->comment->length); | |
961 | else | |
962 | esccomment[0]='\0'; | |
963 | ||
964 | csdb_queuequery(NULL, NULL, "INSERT INTO channels (ID, name, flags, forcemodes, denymodes," | |
965 | "chanlimit, autolimit, banstyle, created, lastactive, statsreset, " | |
966 | "banduration, founder, addedby, suspendby, chantype, totaljoins, tripjoins," | |
967 | "maxusers, tripusers, welcome, topic, chankey, suspendreason, " | |
968 | "comment) VALUES (%u,'%s',%d,%d,%d,%d,%d,%d,%lu,%lu,%lu,%lu,%u," | |
969 | "%u,%u,%d,%u,%u,%u,%u,'%s','%s','%s','%s','%s')", | |
970 | rcp->ID, escname, rcp->flags,rcp->forcemodes, | |
971 | rcp->denymodes,rcp->limit,rcp->autolimit, rcp->banstyle, rcp->created, | |
972 | rcp->lastactive,rcp->statsreset,rcp->banduration, | |
973 | rcp->founder, rcp->addedby, rcp->suspendby, | |
974 | rcp->chantype,rcp->totaljoins,rcp->tripjoins, | |
975 | rcp->maxusers,rcp->tripusers, | |
976 | escwelcome,esctopic,esckey,escreason,esccomment); | |
977 | } | |
978 | ||
979 | void csdb_deletechannel(regchan *rcp) { | |
980 | csdb_queuequery(NULL,NULL,"DELETE FROM channels WHERE ID=%u",rcp->ID); | |
981 | csdb_queuequery(NULL,NULL,"DELETE FROM chanusers WHERE channelID=%u",rcp->ID); | |
982 | csdb_queuequery(NULL,NULL,"DELETE FROM bans WHERE channelID=%u",rcp->ID); | |
983 | } | |
984 | ||
985 | void csdb_deleteuser(reguser *rup) { | |
986 | csdb_queuequery(NULL,NULL,"DELETE FROM users WHERE ID=%u",rup->ID); | |
987 | csdb_queuequery(NULL,NULL,"DELETE FROM chanusers WHERE userID=%u",rup->ID); | |
988 | } | |
989 | ||
990 | void csdb_updateuser(reguser *rup) { | |
991 | char escpassword[25]; | |
992 | char escmasterpass[25]; | |
993 | char escemail[210]; | |
994 | char esclastuserhost[160]; | |
995 | char escreason[510]; | |
996 | char esccomment[510]; | |
997 | char escinfo[210]; | |
998 | ||
999 | PQescapeString(escpassword, rup->password, strlen(rup->password)); | |
1000 | PQescapeString(escmasterpass, rup->masterpass, strlen(rup->masterpass)); | |
1001 | ||
1002 | if (rup->email) | |
1003 | PQescapeString(escemail, rup->email->content, rup->email->length); | |
1004 | else | |
1005 | escemail[0]='\0'; | |
1006 | ||
1007 | if (rup->lastuserhost) | |
1008 | PQescapeString(esclastuserhost, rup->lastuserhost->content, rup->lastuserhost->length); | |
1009 | else | |
1010 | esclastuserhost[0]='\0'; | |
1011 | ||
1012 | if (rup->suspendreason) | |
1013 | PQescapeString(escreason, rup->suspendreason->content, rup->suspendreason->length); | |
1014 | else | |
1015 | escreason[0]='\0'; | |
1016 | ||
1017 | if (rup->comment) | |
1018 | PQescapeString(esccomment, rup->comment->content, rup->comment->length); | |
1019 | else | |
1020 | esccomment[0]='\0'; | |
1021 | ||
1022 | if (rup->info) | |
1023 | PQescapeString(escinfo, rup->info->content, rup->info->length); | |
1024 | else | |
1025 | escinfo[0]='\0'; | |
1026 | ||
1027 | csdb_queuequery(NULL, NULL, "UPDATE users SET lastauth=%lu, lastemailchng=%lu, flags=%u," | |
1028 | "language=%u, suspendby=%u, suspendexp=%lu, password='%s', masterpass='%s', email='%s'," | |
1029 | "lastuserhost='%s', suspendreason='%s', comment='%s', info='%s' WHERE ID=%u", | |
1030 | rup->lastauth, rup->lastemailchange, rup->flags, rup->languageid, rup->suspendby, rup->suspendexp, | |
1031 | escpassword, escmasterpass, escemail, esclastuserhost, escreason, esccomment, escinfo, | |
1032 | rup->ID); | |
1033 | } | |
1034 | ||
1035 | void csdb_createuser(reguser *rup) { | |
1036 | char escpassword[25]; | |
1037 | char escmasterpass[25]; | |
1038 | char escemail[210]; | |
1039 | char esclastuserhost[160]; | |
1040 | char escreason[510]; | |
1041 | char esccomment[510]; | |
1042 | char escusername[35]; | |
1043 | char escinfo[210]; | |
1044 | ||
1045 | PQescapeString(escusername, rup->username, strlen(rup->username)); | |
1046 | PQescapeString(escpassword, rup->password, strlen(rup->password)); | |
1047 | PQescapeString(escmasterpass, rup->masterpass, strlen(rup->masterpass)); | |
1048 | ||
1049 | if (rup->email) | |
1050 | PQescapeString(escemail, rup->email->content, rup->email->length); | |
1051 | else | |
1052 | escemail[0]='\0'; | |
1053 | ||
1054 | if (rup->lastuserhost) | |
1055 | PQescapeString(esclastuserhost, rup->lastuserhost->content, rup->lastuserhost->length); | |
1056 | else | |
1057 | esclastuserhost[0]='\0'; | |
1058 | ||
1059 | if (rup->suspendreason) | |
1060 | PQescapeString(escreason, rup->suspendreason->content, rup->suspendreason->length); | |
1061 | else | |
1062 | escreason[0]='\0'; | |
1063 | ||
1064 | if (rup->comment) | |
1065 | PQescapeString(esccomment, rup->comment->content, rup->comment->length); | |
1066 | else | |
1067 | esccomment[0]='\0'; | |
1068 | ||
1069 | if (rup->info) | |
1070 | PQescapeString(escinfo, rup->info->content, rup->info->length); | |
1071 | else | |
1072 | escinfo[0]='\0'; | |
1073 | ||
1074 | csdb_queuequery(NULL, NULL, "INSERT INTO users (ID, username, created, lastauth, lastemailchng, " | |
1075 | "flags, language, suspendby, suspendexp, password, masterpass, email, lastuserhost, " | |
1076 | "suspendreason, comment, info) VALUES (%u,'%s',%lu,%lu,%lu,%u,%u,%u,%lu,'%s','%s'," | |
1077 | "'%s','%s','%s','%s','%s')", | |
1078 | rup->ID, escusername, rup->created, rup->lastauth, rup->lastemailchange, rup->flags, | |
1079 | rup->languageid, rup->suspendby, rup->suspendexp, | |
1080 | escpassword, escmasterpass, escemail, esclastuserhost, escreason, esccomment, escinfo); | |
1081 | } | |
1082 | ||
1083 | ||
1084 | void csdb_updatechanuser(regchanuser *rcup) { | |
1085 | char escinfo[210]; | |
1086 | ||
1087 | if (rcup->info) | |
1088 | PQescapeString(escinfo, rcup->info->content, rcup->info->length); | |
1089 | else | |
1090 | escinfo[0]='\0'; | |
1091 | ||
1092 | csdb_queuequery(NULL, NULL, "UPDATE chanusers SET flags=%u, changetime=%lu, " | |
1093 | "usetime=%lu, info='%s' WHERE channelID=%u and userID=%u", | |
1094 | rcup->flags, rcup->changetime, rcup->usetime, escinfo, rcup->chan->ID,rcup->user->ID); | |
1095 | } | |
1096 | ||
1097 | void csdb_createchanuser(regchanuser *rcup) { | |
1098 | char escinfo[210]; | |
1099 | ||
1100 | if (rcup->info) | |
1101 | PQescapeString(escinfo, rcup->info->content, rcup->info->length); | |
1102 | else | |
1103 | escinfo[0]='\0'; | |
1104 | ||
1105 | csdb_queuequery(NULL, NULL, "INSERT INTO chanusers VALUES(%u, %u, %u, %lu, %lu, '%s')", | |
1106 | rcup->user->ID, rcup->chan->ID, rcup->flags, rcup->changetime, | |
1107 | rcup->usetime, escinfo); | |
1108 | } | |
1109 | ||
1110 | void csdb_deletechanuser(regchanuser *rcup) { | |
1111 | csdb_queuequery(NULL, NULL, "DELETE FROM chanusers WHERE channelid=%u AND userID=%u", | |
1112 | rcup->chan->ID, rcup->user->ID); | |
1113 | } | |
1114 | ||
1115 | void csdb_createban(regchan *rcp, regban *rbp) { | |
1116 | char escreason[500]; | |
1117 | char banstr[100]; | |
1118 | char escban[200]; | |
1119 | ||
1120 | strcpy(banstr,bantostring(rbp->cbp)); | |
1121 | PQescapeString(escban,banstr,strlen(banstr)); | |
1122 | ||
1123 | if (rbp->reason) | |
1124 | PQescapeString(escreason, rbp->reason->content, rbp->reason->length); | |
1125 | else | |
1126 | escreason[0]='\0'; | |
1127 | ||
1128 | csdb_queuequery(NULL, NULL, "INSERT INTO bans (banID, channelID, userID, hostmask, " | |
1129 | "expiry, reason) VALUES (%u,%u,%u,'%s',%lu,'%s')", rbp->ID, rcp->ID, | |
1130 | rbp->setby, escban, rbp->expiry, escreason); | |
1131 | } | |
1132 | ||
1133 | void csdb_deleteban(regban *rbp) { | |
1134 | csdb_queuequery(NULL, NULL, "DELETE FROM bans WHERE banID=%u", rbp->ID); | |
1135 | } | |
1136 | ||
1137 | /* Help stuff */ | |
1138 | ||
1139 | void csdb_dohelp(nick *np, Command *cmd) { | |
1140 | struct helpinfo *hip; | |
1141 | ||
1142 | hip=(struct helpinfo *)malloc(sizeof(struct helpinfo)); | |
1143 | ||
1144 | hip->numeric=np->numeric; | |
1145 | hip->commandname=getsstring(cmd->command->content, cmd->command->length); | |
1146 | ||
1147 | csdb_queuequery(csdb_dohelp_real, (void *)hip, | |
1148 | "SELECT languageID, fullinfo from help where lower(command)=lower('%s')",cmd->command->content); | |
1149 | } | |
1150 | ||
1151 | void csdb_dohelp_real(void *arg) { | |
1152 | struct helpinfo *hip=arg; | |
1153 | nick *np=getnickbynumeric(hip->numeric); | |
1154 | reguser *rup; | |
1155 | char *result; | |
1156 | PGresult *pgres; | |
1157 | int i,j,num,lang=0; | |
1158 | ||
1159 | pgres=PQgetResult(dbconn); | |
1160 | ||
1161 | if (PQresultStatus(pgres) != PGRES_TUPLES_OK) { | |
1162 | Error("chanserv",ERR_ERROR,"Error loading help text."); | |
1163 | return; | |
1164 | } | |
1165 | ||
1166 | if (PQnfields(pgres)!=2) { | |
1167 | Error("chanserv",ERR_ERROR,"Help text format error."); | |
1168 | return; | |
1169 | } | |
1170 | ||
1171 | num=PQntuples(pgres); | |
1172 | ||
1173 | if (!np) { | |
1174 | PQclear(pgres); | |
1175 | freesstring(hip->commandname); | |
1176 | free(hip); | |
1177 | return; | |
1178 | } | |
1179 | ||
1180 | if ((rup=getreguserfromnick(np))) | |
1181 | lang=rup->languageid; | |
1182 | ||
1183 | result=NULL; | |
1184 | ||
1185 | for (i=0;i<num;i++) { | |
1186 | j=strtoul(PQgetvalue(pgres,i,0),NULL,10); | |
1187 | if ((j==0 && result==NULL) || (j==lang)) { | |
1188 | result=PQgetvalue(pgres,i,1); | |
1189 | if(strlen(result)==0) | |
1190 | result=NULL; | |
1191 | } | |
1192 | } | |
1193 | ||
1194 | if (!result) | |
1195 | chanservstdmessage(np, QM_NOHELP, hip->commandname->content); | |
1196 | else | |
1197 | chanservsendmessage(np, result); | |
1198 | ||
1199 | freesstring(hip->commandname); | |
1200 | free(hip); | |
1201 | } | |
1202 | ||
1203 | void csdb_createmail(reguser *rup, int type) { | |
1204 | char sqlquery[6000]; | |
1205 | char escemail[210]; | |
1206 | ||
1207 | if (type == QMAIL_NEWEMAIL) { | |
1208 | if (rup->email) { | |
1209 | PQescapeString(escemail, rup->email->content, rup->email->length); | |
1210 | sprintf(sqlquery, "INSERT INTO email (userID, emailType, prevEmail) " | |
1211 | "VALUES (%u,%u,'%s')", rup->ID, type, escemail); | |
1212 | } | |
1213 | } else { | |
1214 | sprintf(sqlquery, "INSERT INTO email (userID, emailType) VALUES (%u,%u)", rup->ID, type); | |
1215 | } | |
1216 | ||
1217 | csdb_queuequery(NULL, NULL, "%s", sqlquery); | |
1218 | } |