/[LeafOK_CVS]/pvpgn-1.7.4/src/bnetd/storage_sql.c
ViewVC logotype

Contents of /pvpgn-1.7.4/src/bnetd/storage_sql.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (vendor branch)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch: GNU, MAIN
CVS Tags: pvpgn_1-7-4-0_MIL, arelease, HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-csrc
no message

1 /*
2 * Copyright (C) 2002 TheUndying
3 * Copyright (C) 2002 zap-zero
4 * Copyright (C) 2002,2003 Mihai RUSU (dizzy@rdsnet.ro)
5 * Copyright (C) 2002 Zzzoom
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #include "common/setup_before.h"
23 #ifdef WITH_SQL
24 #include <stdio.h>
25
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 #else
29 # ifdef HAVE_MALLOC_H
30 # include <malloc.h>
31 # endif
32 #endif
33
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #else
37 # ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 # endif
40 #endif
41
42 #include "compat/strdup.h"
43 #include "compat/strcasecmp.h"
44 #include "compat/strncasecmp.h"
45 #include "compat/strtoul.h"
46
47 #ifdef TIME_WITH_SYS_TIME
48 # include <sys/time.h>
49 # include <time.h>
50 #else
51 # ifdef HAVE_SYS_TIME_H
52 # include <sys/time.h>
53 # else
54 # include <time.h>
55 # endif
56 #endif
57
58 #include "common/eventlog.h"
59 #include "prefs.h"
60 #include "common/util.h"
61
62 #define CLAN_INTERNAL_ACCESS
63 #define ACCOUNT_INTERNAL_ACCESS
64 #define TEAM_INTERNAL_ACCESS
65 #include "team.h"
66 #include "account.h"
67 #include "connection.h"
68 #include "clan.h"
69 #undef TEAM_INTERNAL_ACCESS
70 #undef ACCOUNT_INTERNAL_ACCESS
71 #undef CLAN_INTERNAL_ACCESS
72 #include "common/tag.h"
73 #include "common/xalloc.h"
74 #include "common/flags.h"
75 #include "sql_dbcreator.h"
76 #include "storage_sql.h"
77 #ifdef WITH_SQL_MYSQL
78 #include "sql_mysql.h"
79 #endif
80 #ifdef WITH_SQL_PGSQL
81 #include "sql_pgsql.h"
82 #endif
83 #include "common/setup_after.h"
84
85 #define CURRENT_DB_VERSION 150
86
87 #define DB_MAX_ATTRKEY 128
88 #define DB_MAX_ATTRVAL 180
89 #define DB_MAX_TAB 64
90
91 #define SQL_UID_FIELD "uid"
92 #define STORAGE_SQL_DEFAULT_UID 0
93
94 #define SQL_ON_DEMAND 1
95
96 static int sql_init(const char *);
97 static int sql_close(void);
98 static unsigned sql_read_maxuserid(void);
99 static t_storage_info *sql_create_account(char const *);
100 static t_storage_info *sql_get_defacct(void);
101 static int sql_free_info(t_storage_info *);
102 static int sql_read_attrs(t_storage_info *, t_read_attr_func, void *);
103 static void *sql_read_attr(t_storage_info *, const char *);
104 static int sql_write_attrs(t_storage_info *, void *);
105 static int sql_read_accounts(int,t_read_accounts_func, void *);
106 static t_storage_info * sql_read_account(const char *,unsigned);
107 static int sql_cmp_info(t_storage_info *, t_storage_info *);
108 static const char *sql_escape_key(const char *);
109 static int sql_load_clans(t_load_clans_func cb);
110 static int sql_write_clan(void *data);
111 static int sql_remove_clan(int clantag);
112 static int sql_remove_clanmember(int);
113 static int sql_load_teams(t_load_teams_func cb);
114 static int sql_write_team(void *data);
115 static int sql_remove_team(unsigned int teamid);
116
117 t_storage storage_sql = {
118 sql_init,
119 sql_close,
120 sql_read_maxuserid,
121 sql_create_account,
122 sql_get_defacct,
123 sql_free_info,
124 sql_read_attrs,
125 sql_write_attrs,
126 sql_read_attr,
127 sql_read_accounts,
128 sql_read_account,
129 sql_cmp_info,
130 sql_escape_key,
131 sql_load_clans,
132 sql_write_clan,
133 sql_remove_clan,
134 sql_remove_clanmember,
135 sql_load_teams,
136 sql_write_team,
137 sql_remove_team
138 };
139
140 static t_sql_engine *sql = NULL;
141 static unsigned int defacct;
142
143 static int _sql_dbcheck(void);
144 static void _sql_update_DB_v0_to_v150(void);
145
146 #ifndef SQL_ON_DEMAND
147 static char *tables[] = { "BNET", "Record", "profile", "friend", "Team", NULL };
148
149 static const char *_db_add_tab(const char *tab, const char *key)
150 {
151 static char nkey[DB_MAX_ATTRKEY];
152
153 strncpy(nkey, tab, sizeof(nkey) - 1);
154 nkey[strlen(nkey) + 1] = '\0';
155 nkey[strlen(nkey)] = '_';
156 strncpy(nkey + strlen(nkey), key, sizeof(nkey) - strlen(nkey));
157 return nkey;
158 }
159
160 #endif /* SQL_ON_DEMAND */
161
162 static int _db_get_tab(const char *key, char **ptab, char **pcol)
163 {
164 static char tab[DB_MAX_ATTRKEY];
165 static char col[DB_MAX_ATTRKEY];
166
167 strncpy(tab, key, DB_MAX_TAB - 1);
168 tab[DB_MAX_TAB - 1] = 0;
169
170 if (!strchr(tab, '_'))
171 return -1;
172
173
174 *(strchr(tab, '_')) = 0;
175 strncpy(col, key + strlen(tab) + 1, DB_MAX_TAB - 1);
176 col[DB_MAX_TAB - 1] = 0;
177 /* return tab and col as 2 static buffers */
178 *ptab = tab;
179 *pcol = col;
180 return 0;
181 }
182
183 static int sql_init(const char *dbpath)
184 {
185 char *tok, *path, *tmp, *p;
186 const char *dbhost = NULL;
187 const char *dbname = NULL;
188 const char *dbuser = NULL;
189 const char *dbpass = NULL;
190 const char *driver = NULL;
191 const char *dbport = NULL;
192 const char *dbsocket = NULL;
193 const char *def = NULL;
194
195 path = xstrdup(dbpath);
196 tmp = path;
197 while ((tok = strtok(tmp, ";")) != NULL)
198 {
199 tmp = NULL;
200 if ((p = strchr(tok, '=')) == NULL)
201 {
202 eventlog(eventlog_level_error, __FUNCTION__, "invalid storage_path, no '=' present in token");
203 xfree((void *) path);
204 return -1;
205 }
206 *p = '\0';
207 if (strcasecmp(tok, "host") == 0)
208 dbhost = p + 1;
209 else if (strcasecmp(tok, "mode") == 0)
210 driver = p + 1;
211 else if (strcasecmp(tok, "name") == 0)
212 dbname = p + 1;
213 else if (strcasecmp(tok, "port") == 0)
214 dbport = p + 1;
215 else if (strcasecmp(tok, "socket") == 0)
216 dbsocket = p + 1;
217 else if (strcasecmp(tok, "user") == 0)
218 dbuser = p + 1;
219 else if (strcasecmp(tok, "pass") == 0)
220 dbpass = p + 1;
221 else if (strcasecmp(tok, "default") == 0)
222 def = p + 1;
223 else
224 eventlog(eventlog_level_warn, __FUNCTION__, "unknown token in storage_path : '%s'", tok);
225 }
226
227 if (driver == NULL)
228 {
229 eventlog(eventlog_level_error, __FUNCTION__, "no mode specified");
230 xfree((void *) path);
231 return -1;
232 }
233
234 if (def == NULL)
235 defacct = STORAGE_SQL_DEFAULT_UID;
236 else
237 defacct = atoi(def);
238
239 do
240 {
241 #ifdef WITH_SQL_MYSQL
242 if (strcasecmp(driver, "mysql") == 0)
243 {
244 sql = &sql_mysql;
245 if (sql->init(dbhost, dbport, dbsocket, dbname, dbuser, dbpass))
246 {
247 eventlog(eventlog_level_error, __FUNCTION__, "got error init db");
248 sql = NULL;
249 xfree((void *) path);
250 return -1;
251 }
252 break;
253 }
254 #endif /* WITH_SQL_MYSQL */
255 #ifdef WITH_SQL_PGSQL
256 if (strcasecmp(driver, "pgsql") == 0)
257 {
258 sql = &sql_pgsql;
259 if (sql->init(dbhost, dbport, dbsocket, dbname, dbuser, dbpass))
260 {
261 eventlog(eventlog_level_error, __FUNCTION__, "got error init db");
262 sql = NULL;
263 xfree((void *) path);
264 return -1;
265 }
266 break;
267 }
268 #endif /* WITH_SQL_PGSQL */
269 eventlog(eventlog_level_error, __FUNCTION__, "no driver found for '%s'", driver);
270 xfree((void *) path);
271 return -1;
272 }
273 while (0);
274
275 xfree((void *) path);
276
277 if (_sql_dbcheck())
278 {
279 eventlog(eventlog_level_error, __FUNCTION__, "got error from dbcheck");
280 sql->close();
281 return -1;
282 }
283
284 return 0;
285 }
286
287 static int sql_close(void)
288 {
289 if (sql == NULL)
290 {
291 eventlog(eventlog_level_error, __FUNCTION__, "sql not initilized");
292 return -1;
293 }
294
295 sql->close();
296 sql = NULL;
297 return 0;
298 }
299
300 static unsigned sql_read_maxuserid(void)
301 {
302 t_sql_res *result;
303 t_sql_row *row;
304 long maxuid;
305
306 if (sql == NULL)
307 {
308 eventlog(eventlog_level_error, __FUNCTION__, "sql not initilized");
309 return 0;
310 }
311
312 if ((result = sql->query_res("SELECT max(uid) FROM BNET")) == NULL) {
313 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"SELECT max(uid) FROM BNET\"");
314 return 0;
315 }
316
317 row = sql->fetch_row(result);
318 if (row == NULL || row[0] == NULL)
319 {
320 sql->free_result(result);
321 eventlog(eventlog_level_error, __FUNCTION__, "got NULL max");
322 return 0;
323 }
324
325 maxuid = atol(row[0]);
326 sql->free_result(result);
327 if (maxuid < 0)
328 {
329 eventlog(eventlog_level_error, __FUNCTION__, "got invalid maxuserid");
330 return 0;
331 }
332
333 return maxuid;
334 }
335
336 static t_storage_info *sql_create_account(char const *username)
337 {
338 char query[1024];
339 t_sql_res *result = NULL;
340 t_sql_row *row;
341 int uid = maxuserid + 1;
342 char str_uid[32];
343 t_storage_info *info;
344
345 if (!sql)
346 {
347 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
348 return NULL;
349 }
350
351 sprintf(str_uid, "%u", uid);
352
353 sprintf(query, "SELECT count(*) FROM BNET WHERE acct_username='%s'", username);
354 if ((result = sql->query_res(query)) != NULL)
355 {
356 int num;
357
358 row = sql->fetch_row(result);
359 if (row == NULL || row[0] == NULL)
360 {
361 sql->free_result(result);
362 eventlog(eventlog_level_error, __FUNCTION__, "got NULL count");
363 return NULL;
364 }
365 num = atol(row[0]);
366 sql->free_result(result);
367 if (num > 0)
368 {
369 eventlog(eventlog_level_error, __FUNCTION__, "got existant username");
370 return NULL;
371 }
372 } else
373 {
374 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
375 return NULL;
376 }
377
378 info = xmalloc(sizeof(t_sql_info));
379 *((unsigned int *) info) = uid;
380 sprintf(query, "DELETE FROM BNET WHERE uid = '%s';", str_uid);
381 sql->query(query);
382 sprintf(query, "INSERT INTO BNET (uid) VALUES('%s');", str_uid);
383 if (sql->query(query))
384 {
385 eventlog(eventlog_level_error, __FUNCTION__, "user insert failed");
386 xfree((void *) info);
387 return NULL;
388 }
389
390 sprintf(query, "DELETE FROM profile WHERE uid = '%s';", str_uid);
391 sql->query(query);
392 sprintf(query, "INSERT INTO profile (uid) VALUES('%s');", str_uid);
393 if (sql->query(query))
394 {
395 eventlog(eventlog_level_error, __FUNCTION__, "user insert failed");
396 xfree((void *) info);
397 return NULL;
398 }
399
400 sprintf(query, "DELETE FROM Record WHERE uid = '%s';", str_uid);
401 sql->query(query);
402 sprintf(query, "INSERT INTO Record (uid) VALUES('%s');", str_uid);
403 if (sql->query(query))
404 {
405 eventlog(eventlog_level_error, __FUNCTION__, "user insert failed");
406 xfree((void *) info);
407 return NULL;
408 }
409
410 sprintf(query, "DELETE FROM friend WHERE uid = '%s';", str_uid);
411 sql->query(query);
412 sprintf(query, "INSERT INTO friend (uid) VALUES('%s');", str_uid);
413 if (sql->query(query))
414 {
415 eventlog(eventlog_level_error, __FUNCTION__, "user insert failed");
416 xfree((void *) info);
417 return NULL;
418 }
419
420 return info;
421 }
422
423 static int sql_read_attrs(t_storage_info * info, t_read_attr_func cb, void *data)
424 {
425 #ifndef SQL_ON_DEMAND
426 char query[1024];
427 t_sql_res *result = NULL;
428 t_sql_row *row;
429 char **tab;
430 unsigned int uid;
431
432 if (!sql)
433 {
434 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
435 return -1;
436 }
437
438 if (info == NULL)
439 {
440 eventlog(eventlog_level_error, __FUNCTION__, "got NULL storage info");
441 return -1;
442 }
443
444 if (cb == NULL)
445 {
446 eventlog(eventlog_level_error, __FUNCTION__, "got NULL callback");
447 return -1;
448 }
449
450 uid = *((unsigned int *) info);
451
452 for (tab = tables; *tab; tab++)
453 {
454 sprintf(query, "SELECT * FROM %s WHERE uid='%u'", *tab, uid);
455
456 // eventlog(eventlog_level_trace, __FUNCTION__, "query: \"%s\"",query);
457
458 if ((result = sql->query_res(query)) != NULL && sql->num_rows(result) == 1 && sql->num_fields(result) > 1)
459 {
460 unsigned int i;
461 t_sql_field *fields, *fentry;
462
463 if ((fields = sql->fetch_fields(result)) == NULL)
464 {
465 eventlog(eventlog_level_error, "db_get_attributes", "could not fetch the fields");
466 sql->free_result(result);
467 return -1;
468 }
469
470 if (!(row = sql->fetch_row(result)))
471 {
472 eventlog(eventlog_level_error, __FUNCTION__, "could not fetch row");
473 sql->free_fields(fields);
474 sql->free_result(result);
475 return -1;
476 }
477
478 for (i = 0, fentry = fields; *fentry; fentry++, i++)
479 { /* we have to skip "uid" */
480 char *output;
481 /* we ignore the field used internally by sql */
482 if (strcmp(*fentry, SQL_UID_FIELD) == 0)
483 continue;
484
485 // eventlog(eventlog_level_trace, __FUNCTION__, "read key (step1): '%s' val: '%s'", _db_add_tab(*tab, *fentry), unescape_chars(row[i]));
486 if (row[i] == NULL)
487 continue; /* its an NULL value sql field */
488
489 // eventlog(eventlog_level_trace, __FUNCTION__, "read key (step2): '%s' val: '%s'", _db_add_tab(*tab, *fentry), unescape_chars(row[i]));
490 if (cb(_db_add_tab(*tab, *fentry), (output = unescape_chars(row[i])), data))
491 eventlog(eventlog_level_error, __FUNCTION__, "got error from callback on UID: %u", uid);
492 if (output)
493 xfree((void *) output);
494 // eventlog(eventlog_level_trace, __FUNCTION__, "read key (final): '%s' val: '%s'", _db_add_tab(*tab, *fentry), unescape_chars(row[i]));
495 }
496
497 sql->free_fields(fields);
498 }
499 if (result)
500 sql->free_result(result);
501 }
502 #endif /* SQL_ON_DEMAND */
503 return 0;
504 }
505
506 static void *sql_read_attr(t_storage_info * info, const char *key)
507 {
508 #ifdef SQL_ON_DEMAND
509 char query[1024];
510 t_sql_res *result = NULL;
511 t_sql_row *row;
512 char *tab, *col;
513 unsigned int uid;
514 t_attribute *attr;
515
516 if (!sql)
517 {
518 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
519 return NULL;
520 }
521
522 if (info == NULL)
523 {
524 eventlog(eventlog_level_error, __FUNCTION__, "got NULL storage info");
525 return NULL;
526 }
527
528 if (key == NULL)
529 {
530 eventlog(eventlog_level_error, __FUNCTION__, "got NULL key");
531 return NULL;
532 }
533
534 uid = *((unsigned int *) info);
535
536 if (_db_get_tab(key, &tab, &col) < 0)
537 {
538 eventlog(eventlog_level_error, __FUNCTION__, "error from db_get_tab");
539 return NULL;
540 }
541
542 sprintf(query, "SELECT %s FROM %s WHERE " SQL_UID_FIELD " = %d", col, tab, uid);
543 if ((result = sql->query_res(query)) == NULL)
544 return NULL;
545
546 if (sql->num_rows(result) != 1)
547 {
548 // eventlog(eventlog_level_debug, __FUNCTION__, "wrong numer of rows from query (%s)", query);
549 sql->free_result(result);
550 return NULL;
551 }
552
553 if (!(row = sql->fetch_row(result)))
554 {
555 eventlog(eventlog_level_error, __FUNCTION__, "could not fetch row");
556 sql->free_result(result);
557 return NULL;
558 }
559
560 if (row[0] == NULL)
561 {
562 // eventlog(eventlog_level_debug, __FUNCTION__, "NULL value from query (%s)", query);
563 sql->free_result(result);
564 return NULL;
565 }
566
567 attr = (t_attribute *) xmalloc(sizeof(t_attribute));
568 attr->key = xstrdup(key);
569 attr->val = xstrdup(row[0]);
570
571 sql->free_result(result);
572
573 attr->dirty = 0;
574 return (void *) attr;
575 #else
576 return NULL;
577 #endif /* SQL_ON_DEMAND */
578 }
579
580 /* write ONLY dirty attributes */
581 int sql_write_attrs(t_storage_info * info, void *attrs)
582 {
583 char query[1024];
584 char escape[DB_MAX_ATTRVAL * 2 + 1]; /* sql docs say the escape can take a maximum of double original size + 1 */
585 char safeval[DB_MAX_ATTRVAL];
586 char *p, *tab, *col;
587 t_attribute *attr;
588 unsigned int uid;
589
590 if (!sql)
591 {
592 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
593 return -1;
594 }
595
596 if (info == NULL)
597 {
598 eventlog(eventlog_level_error, __FUNCTION__, "got NULL sql info");
599 return -1;
600 }
601
602 if (attrs == NULL)
603 {
604 eventlog(eventlog_level_error, __FUNCTION__, "got NULL attributes list");
605 return -1;
606 }
607
608 uid = *((unsigned int *) info);
609
610 for (attr = (t_attribute *) attrs; attr; attr = attr->next)
611 {
612 if (!attr->dirty)
613 continue; /* save ONLY dirty attributes */
614
615 if (attr->key == NULL)
616 {
617 eventlog(eventlog_level_error, __FUNCTION__, "found NULL key in attributes list");
618 continue;
619 }
620
621 if (attr->val == NULL)
622 {
623 eventlog(eventlog_level_error, __FUNCTION__, "found NULL value in attributes list");
624 continue;
625 }
626
627 if (_db_get_tab(attr->key, &tab, &col) < 0)
628 {
629 eventlog(eventlog_level_error, __FUNCTION__, "error from db_get_tab");
630 continue;
631 }
632
633 strncpy(safeval, attr->val, DB_MAX_ATTRVAL - 1);
634 safeval[DB_MAX_ATTRVAL - 1] = 0;
635 for (p = safeval; *p; p++)
636 if (*p == '\'') /* value shouldn't contain ' */
637 *p = '"';
638
639 sql->escape_string(escape, safeval, strlen(safeval));
640
641 strcpy(query, "UPDATE ");
642 strncat(query, tab, 64);
643 strcat(query, " SET ");
644 strncat(query, col, 64);
645 strcat(query, "='");
646 strcat(query, escape);
647 strcat(query, "' WHERE uid='");
648 sprintf(query + strlen(query), "%u", uid);
649 strcat(query, "'");
650
651 // eventlog(eventlog_level_trace, "db_set", "update query: %s", query);
652
653 if (sql->query(query) || !sql->affected_rows())
654 {
655 char query2[512];
656
657 // eventlog(eventlog_level_debug, __FUNCTION__, "trying to insert new column %s", col);
658 strcpy(query2, "ALTER TABLE ");
659 strncat(query2, tab, DB_MAX_TAB);
660 strcat(query2, " ADD COLUMN ");
661 strncat(query2, col, DB_MAX_TAB);
662 strcat(query2, " VARCHAR(128);");
663
664 // eventlog(eventlog_level_trace, __FUNCTION__, "alter query: %s", query2);
665 sql->query(query2);
666
667 /* try query again */
668 // eventlog(eventlog_level_trace, "db_set", "retry insert query: %s", query);
669 if (sql->query(query) || !sql->affected_rows())
670 {
671 // Tried everything, now trying to insert that user to the table for the first time
672 sprintf(query2, "INSERT INTO %s (uid,%s) VALUES ('%u','%s')", tab, col, uid, escape);
673 // eventlog(eventlog_level_error, __FUNCTION__, "update failed so tried INSERT for the last chance");
674 if (sql->query(query2))
675 {
676 eventlog(eventlog_level_error, __FUNCTION__, "could not INSERT attribute '%s'->'%s'", attr->key, attr->val);
677 continue;
678 }
679 }
680 }
681 }
682
683 return 0;
684 }
685
686 static int sql_read_accounts(int flag,t_read_accounts_func cb, void *data)
687 {
688 char query[1024];
689 t_sql_res *result = NULL;
690 t_sql_row *row;
691 t_storage_info *info;
692
693 if (!sql)
694 {
695 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
696 return -1;
697 }
698
699 if (cb == NULL)
700 {
701 eventlog(eventlog_level_error, __FUNCTION__, "get NULL callback");
702 return -1;
703 }
704
705 /* don't actually load anything here if ST_FORCE is not set as SQL is indexed */
706 if (!FLAG_ISSET(flag,ST_FORCE)) return 1;
707
708 strcpy(query, "SELECT uid FROM BNET");
709 if ((result = sql->query_res(query)) != NULL)
710 {
711 if (sql->num_rows(result) <= 1)
712 {
713 sql->free_result(result);
714 return 0; /* empty user list */
715 }
716
717 while ((row = sql->fetch_row(result)) != NULL)
718 {
719 if (row[0] == NULL)
720 {
721 eventlog(eventlog_level_error, __FUNCTION__, "got NULL uid from db");
722 continue;
723 }
724
725 if ((unsigned int) atoi(row[0]) == defacct)
726 continue; /* skip default account */
727
728 info = xmalloc(sizeof(t_sql_info));
729 *((unsigned int *) info) = atoi(row[0]);
730 cb(info, data);
731 }
732 sql->free_result(result);
733 } else
734 {
735 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
736 return -1;
737 }
738
739 return 0;
740 }
741
742 static t_storage_info * sql_read_account(const char *name, unsigned uid)
743 {
744 char query[1024];
745 t_sql_res *result = NULL;
746 t_sql_row *row;
747 t_storage_info *info;
748
749 if (!sql)
750 {
751 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
752 return NULL;
753 }
754
755 /* SELECT uid from BNET WHERE uid=x sounds stupid, I agree but its a clean
756 * way to check for account existence by an uid */
757 if (name)
758 sprintf(query, "SELECT uid FROM BNET WHERE acct_username='%s'", name);
759 else
760 sprintf(query, "SELECT uid FROM BNET WHERE uid=%u", uid);
761 result = sql->query_res(query);
762 if (!result) {
763 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
764 return NULL;
765 }
766
767 if (sql->num_rows(result) < 1)
768 {
769 sql->free_result(result);
770 return NULL; /* empty user list */
771 }
772
773 row = sql->fetch_row(result);
774 if (!row) {
775 /* could not fetch row, this should not happen */
776 sql->free_result(result);
777 return NULL;
778 }
779
780 if (row[0] == NULL)
781 /* empty UID field */
782 eventlog(eventlog_level_error, __FUNCTION__, "got NULL uid from db");
783 else if ((unsigned int) atoi(row[0]) == defacct);
784 /* skip default account */
785 else {
786 info = xmalloc(sizeof(t_sql_info));
787 *((unsigned int *) info) = atoi(row[0]);
788 sql->free_result(result);
789 return info;
790 }
791
792 sql->free_result(result);
793 return NULL;
794 }
795
796 static int sql_cmp_info(t_storage_info * info1, t_storage_info * info2)
797 {
798 return *((unsigned int *) info1) != *((unsigned int *) info2);
799 }
800
801 static int sql_free_info(t_storage_info * info)
802 {
803 if (info)
804 xfree((void *) info);
805
806 return 0;
807 }
808
809 static t_storage_info *sql_get_defacct(void)
810 {
811 t_storage_info *info;
812
813 info = xmalloc(sizeof(t_sql_info));
814 *((unsigned int *) info) = defacct;
815
816 return info;
817 }
818
819 static const char *sql_escape_key(const char *key)
820 {
821 const char *newkey = key;
822 char *p;
823 int idx;
824
825 for(idx = 0, p = (char *)newkey; *p; p++, idx++)
826 if ((*p < '0' || *p > '9') && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z')) {
827 newkey = xstrdup(key);
828 p = (char *)(newkey + idx);
829 *(p++) = '_';
830 for(; *p; p++)
831 if ((*p < '0' || *p > '9') && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z'))
832 *p = '_';
833 break;
834 }
835
836 return newkey;
837 }
838
839 int db_get_version(void)
840 {
841 t_sql_res *result = NULL;
842 t_sql_row *row;
843 int version = 0;
844
845 if ((result = sql->query_res("SELECT value FROM pvpgn WHERE name = 'db_version'")) == NULL)
846 return 0;
847 if (sql->num_rows(result) == 1 && (row = sql->fetch_row(result)) != NULL && row[0] != NULL)
848 version = atoi(row[0]);
849
850 sql->free_result(result);
851
852 return version;
853 }
854
855 void _sql_db_set_version(int version)
856 {
857 char query[1024];
858
859 sprintf(query, "UPDATE pvpgn SET value = '%d' WHERE name = 'db_version';", version);
860 if (sql->query(query))
861 {
862 sql->query("CREATE TABLE pvpgn (name varchar(128) NOT NULL PRIMARY KEY, value varchar(255));");
863 sprintf(query, "INSERT INTO pvpgn (name, value) VALUES('db_version', '%d');", version);
864 sql->query(query);
865 }
866 }
867
868 extern int _sql_dbcheck(void)
869 {
870 int version = 0;
871
872 sql_dbcreator(sql);
873
874 while ((version = db_get_version()) != CURRENT_DB_VERSION)
875 {
876
877 switch (version)
878 {
879 case 0:
880 _sql_update_DB_v0_to_v150();
881 break;
882 default:
883 eventlog(eventlog_level_error, __FUNCTION__, "unknown PvPGN DB version, aborting");
884 return -1;
885 }
886 }
887
888 return 0;
889 }
890
891 static void _sql_update_DB_v0_to_v150(void)
892 {
893 t_sql_res *result;
894 t_sql_field *fields, *fentry;
895 char query[1024];
896
897 eventlog(eventlog_level_info, __FUNCTION__, "updating your PvPGN SQL DB...");
898
899 if ((result = sql->query_res("SELECT * FROM Record;")) != NULL)
900 {
901 if ((fields = sql->fetch_fields(result)) != NULL)
902 {
903 for (fentry = fields; *fentry; fentry++)
904 {
905 if (strncasecmp(*fentry, "WAR3_", 5) == 0)
906 continue; // prevent converting over and over again
907 if (strncasecmp(*fentry, "W3XP_", 5) == 0)
908 continue;
909 if (strncasecmp(*fentry, CLIENTTAG_STARCRAFT, 4) == 0)
910 continue;
911 if (strncasecmp(*fentry, CLIENTTAG_BROODWARS, 4) == 0)
912 continue;
913 if (strncasecmp(*fentry, CLIENTTAG_WARCIIBNE, 4) == 0)
914 continue;
915 if (strncasecmp(*fentry, CLIENTTAG_DIABLO2DV, 4) == 0)
916 continue;
917 if (strncasecmp(*fentry, CLIENTTAG_DIABLO2XP, 4) == 0)
918 continue;
919 if (strncasecmp(*fentry, CLIENTTAG_DIABLORTL, 4) == 0)
920 continue;
921 if (strncasecmp(*fentry, CLIENTTAG_DIABLOSHR, 4) == 0)
922 continue;
923 if (strncasecmp(*fentry, CLIENTTAG_SHAREWARE, 4) == 0)
924 continue;
925 if (strcmp(*fentry, SQL_UID_FIELD) == 0)
926 continue;
927
928 sprintf(query, "ALTER TABLE Record CHANGE %s WAR3_%s int default '0';", *fentry, *fentry);
929 sql->query(query);
930 sprintf(query, "ALTER TABLE Record ADD W3XP_%s int default '0';", *fentry);
931 sql->query(query);
932 }
933 sql->free_fields(fields);
934 }
935 sql->free_result(result);
936 }
937
938 if ((result = sql->query_res("SELECT * FROM Team;")) != NULL)
939 {
940 if ((fields = sql->fetch_fields(result)) != NULL)
941 {
942 for (fentry = fields; *fentry; fentry++)
943 {
944 if (strncmp(*fentry, "WAR3_", 5) == 0)
945 continue;
946 if (strncmp(*fentry, "W3XP_", 5) == 0)
947 continue;
948 if (strcmp(*fentry, SQL_UID_FIELD) == 0)
949 continue;
950
951 sprintf(query, "ALTER TABLE Team CHANGE %s WAR3_%s varchar(128);", *fentry, *fentry);
952 sql->query(query);
953 }
954 sql->free_fields(fields);
955 }
956 sql->free_result(result);
957 }
958
959 _sql_db_set_version(150);
960
961 eventlog(eventlog_level_info, __FUNCTION__, "successfully updated your DB");
962 }
963
964 static int sql_load_clans(t_load_clans_func cb)
965 {
966 t_sql_res *result;
967 t_sql_res *result2;
968 t_sql_row *row;
969 t_sql_row *row2;
970 char query[1024];
971 t_clan *clan;
972 int member_uid;
973 t_clanmember *member;
974
975 if (!sql)
976 {
977 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
978 return -1;
979 }
980
981 if (cb == NULL)
982 {
983 eventlog(eventlog_level_error, __FUNCTION__, "get NULL callback");
984 return -1;
985 }
986
987 strcpy(query, "SELECT cid, short, name, motd, creation_time FROM clan WHERE cid > 0");
988 if ((result = sql->query_res(query)) != NULL)
989 {
990 if (sql->num_rows(result) < 1)
991 {
992 sql->free_result(result);
993 return 0; /* empty clan list */
994 }
995
996 while ((row = sql->fetch_row(result)) != NULL)
997 {
998 if (row[0] == NULL)
999 {
1000 eventlog(eventlog_level_error, __FUNCTION__, "got NULL cid from db");
1001 continue;
1002 }
1003
1004 clan = xmalloc(sizeof(t_clan));
1005
1006 if (!(clan->clanid = atoi(row[0])))
1007 {
1008 eventlog(eventlog_level_error, __FUNCTION__, "got bad cid");
1009 sql->free_result(result);
1010 return -1;
1011 }
1012
1013 clan->clantag = atoi(row[1]);
1014
1015 clan->clanname = xstrdup(row[2]);
1016 clan->clan_motd = xstrdup(row[3]);
1017 clan->creation_time = atoi(row[4]);
1018 clan->created = 1;
1019 clan->modified = 0;
1020 clan->channel_type = prefs_get_clan_channel_default_private();
1021 clan->members = list_create();
1022
1023 sprintf(query, "SELECT uid, status, join_time FROM clanmember WHERE cid='%u'", clan->clanid);
1024
1025 if ((result2 = sql->query_res(query)) != NULL)
1026 {
1027 if (sql->num_rows(result2) >= 1)
1028 while ((row2 = sql->fetch_row(result2)) != NULL)
1029 {
1030 member = xmalloc(sizeof(t_clanmember));
1031 if (row2[0] == NULL)
1032 {
1033 eventlog(eventlog_level_error, __FUNCTION__, "got NULL uid from db");
1034 continue;
1035 }
1036 if (!(member_uid = atoi(row2[0])))
1037 continue;
1038 if (!(member->memberacc = accountlist_find_account_by_uid(member_uid)))
1039 {
1040 eventlog(eventlog_level_error, __FUNCTION__, "cannot find uid %u", member_uid);
1041 xfree((void *) member);
1042 continue;
1043 }
1044 member->status = atoi(row2[1]);
1045 member->join_time = atoi(row2[2]);
1046 member->clan = clan;
1047
1048 if ((member->status == CLAN_NEW) && (time(NULL) - member->join_time > prefs_get_clan_newer_time() * 3600))
1049 {
1050 member->status = CLAN_PEON;
1051 clan->modified = 1;
1052 member->modified = 1;
1053 }
1054
1055 list_append_data(clan->members, member);
1056
1057 account_set_clanmember(member->memberacc, member);
1058 eventlog(eventlog_level_trace, __FUNCTION__, "added member: uid: %i status: %c join_time: %u", member_uid, member->status + '0', (unsigned) member->join_time);
1059 }
1060 sql->free_result(result2);
1061 cb(clan);
1062 } else
1063 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
1064 }
1065
1066 sql->free_result(result);
1067 } else
1068 {
1069 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
1070 return -1;
1071 }
1072 return 0;
1073 }
1074
1075 static int sql_write_clan(void *data)
1076 {
1077 char query[1024];
1078 t_sql_res *result;
1079 t_sql_row *row;
1080 t_elem *curr;
1081 t_clanmember *member;
1082 t_clan *clan = (t_clan *) data;
1083 int num;
1084
1085 if (!sql)
1086 {
1087 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1088 return -1;
1089 }
1090
1091 sprintf(query, "SELECT count(*) FROM clan WHERE cid='%u'", clan->clanid);
1092 if ((result = sql->query_res(query)) != NULL)
1093 {
1094 row = sql->fetch_row(result);
1095 if (row == NULL || row[0] == NULL)
1096 {
1097 sql->free_result(result);
1098 eventlog(eventlog_level_error, __FUNCTION__, "got NULL count");
1099 return -1;
1100 }
1101 num = atol(row[0]);
1102 sql->free_result(result);
1103 if (num < 1)
1104 sprintf(query, "INSERT INTO clan (cid, short, name, motd, creation_time) VALUES('%u', '%d', '%s', '%s', '%u')", clan->clanid, clan->clantag, clan->clanname, clan->clan_motd, (unsigned) clan->creation_time);
1105 else
1106 sprintf(query, "UPDATE clan SET short='%d', name='%s', motd='%s', creation_time='%u' WHERE cid='%u'", clan->clantag, clan->clanname, clan->clan_motd, (unsigned) clan->creation_time, clan->clanid);
1107 if (sql->query(query) < 0)
1108 {
1109 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1110 return -1;
1111 }
1112 LIST_TRAVERSE(clan->members, curr)
1113 {
1114 unsigned int uid;
1115
1116 if (!(member = elem_get_data(curr)))
1117 {
1118 eventlog(eventlog_level_error, __FUNCTION__, "got NULL elem in list");
1119 continue;
1120 }
1121 if ((member->status == CLAN_NEW) && (time(NULL) - member->join_time > prefs_get_clan_newer_time() * 3600))
1122 {
1123 member->status = CLAN_PEON;
1124 member->modified = 1;
1125 }
1126 if (member->modified)
1127 {
1128 uid = account_get_uid(member->memberacc);
1129 sprintf(query, "SELECT count(*) FROM clanmember WHERE uid='%u'", uid);
1130 if ((result = sql->query_res(query)) != NULL)
1131 {
1132 row = sql->fetch_row(result);
1133 if (row == NULL || row[0] == NULL)
1134 {
1135 sql->free_result(result);
1136 eventlog(eventlog_level_error, __FUNCTION__, "got NULL count");
1137 return -1;
1138 }
1139 num = atol(row[0]);
1140 sql->free_result(result);
1141 if (num < 1)
1142 sprintf(query, "INSERT INTO clanmember (cid, uid, status, join_time) VALUES('%u', '%u', '%d', '%u')", clan->clanid, uid, member->status, (unsigned) member->join_time);
1143 else
1144 sprintf(query, "UPDATE clanmember SET cid='%u', status='%d', join_time='%u' WHERE uid='%u'", clan->clanid, member->status, (unsigned) member->join_time, uid);
1145 if (sql->query(query) < 0)
1146 {
1147 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1148 return -1;
1149 }
1150 } else
1151 {
1152 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1153 return -1;
1154 }
1155 member->modified = 0;
1156 }
1157 }
1158 } else
1159 {
1160 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1161 return -1;
1162 }
1163
1164 return 0;
1165 }
1166
1167 static int sql_remove_clan(int clantag)
1168 {
1169 char query[1024];
1170 t_sql_res *result;
1171 t_sql_row *row;
1172
1173 if (!sql)
1174 {
1175 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1176 return -1;
1177 }
1178
1179 sprintf(query, "SELECT cid FROM clan WHERE short = '%d'", clantag);
1180 if (!(result = sql->query_res(query)))
1181 {
1182 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
1183 return -1;
1184 }
1185
1186 if (sql->num_rows(result) != 1)
1187 {
1188 sql->free_result(result);
1189 return -1; /*clan not found or found more than 1 */
1190 }
1191
1192 if ((row = sql->fetch_row(result)))
1193 {
1194 unsigned int cid = atoi(row[0]);
1195 sprintf(query, "DELETE FROM clanmember WHERE cid='%u'", cid);
1196 if (sql->query(query) != 0)
1197 return -1;
1198 sprintf(query, "DELETE FROM clan WHERE cid='%u'", cid);
1199 if (sql->query(query) != 0)
1200 return -1;
1201 }
1202
1203 sql->free_result(result);
1204
1205 return 0;
1206 }
1207
1208 static int sql_remove_clanmember(int uid)
1209 {
1210 char query[1024];
1211
1212 if (!sql)
1213 {
1214 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1215 return -1;
1216 }
1217
1218 sprintf(query, "DELETE FROM clanmember WHERE uid='%u'", uid);
1219 if (sql->query(query) != 0)
1220 {
1221 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1222 return -1;
1223 }
1224
1225 return 0;
1226 }
1227
1228 static int sql_load_teams(t_load_teams_func cb)
1229 {
1230 t_sql_res *result;
1231 t_sql_row *row;
1232 char query[1024];
1233 t_team *team;
1234 int i;
1235
1236 if (!sql)
1237 {
1238 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1239 return -1;
1240 }
1241
1242 if (cb == NULL)
1243 {
1244 eventlog(eventlog_level_error, __FUNCTION__, "get NULL callback");
1245 return -1;
1246 }
1247
1248 strcpy(query, "SELECT teamid, size, clienttag, lastgame, member1, member2, member3, member4, wins,losses, xp, level, rank FROM arrangedteam WHERE teamid > 0");
1249 if ((result = sql->query_res(query)) != NULL)
1250 {
1251 if (sql->num_rows(result) < 1)
1252 {
1253 sql->free_result(result);
1254 return 0; /* empty team list */
1255 }
1256
1257 while ((row = sql->fetch_row(result)) != NULL)
1258 {
1259 if (row[0] == NULL)
1260 {
1261 eventlog(eventlog_level_error, __FUNCTION__, "got NULL teamid from db");
1262 continue;
1263 }
1264
1265 team = xmalloc(sizeof(t_team));
1266
1267 if (!(team->teamid = atoi(row[0])))
1268 {
1269 eventlog(eventlog_level_error, __FUNCTION__, "got bad teamid");
1270 sql->free_result(result);
1271 return -1;
1272 }
1273
1274 team->size = atoi(row[1]);
1275 team->clienttag=tag_str_to_uint(row[2]);
1276 team->lastgame = strtoul(row[3],NULL,10);
1277 team->teammembers[0] = strtoul(row[4],NULL,10);
1278 team->teammembers[1] = strtoul(row[5],NULL,10);
1279 team->teammembers[2] = strtoul(row[6],NULL,10);
1280 team->teammembers[3] = strtoul(row[7],NULL,10);
1281
1282 for (i=0; i<MAX_TEAMSIZE;i++)
1283 {
1284 if (i<team->size)
1285 {
1286 if ((team->teammembers[i]==0))
1287 {
1288 eventlog(eventlog_level_error,__FUNCTION__,"invalid team data: too few members");
1289 free((void *)team);
1290 goto load_team_failure;
1291 }
1292 }
1293 else
1294 {
1295 if ((team->teammembers[i]!=0))
1296 {
1297 eventlog(eventlog_level_error,__FUNCTION__,"invalid team data: too many members");
1298 free((void *)team);
1299 goto load_team_failure;
1300 }
1301
1302 }
1303 team->members[i] = NULL;
1304 }
1305
1306 team->wins = atoi(row[8]);
1307 team->losses = atoi(row[9]);
1308 team->xp = atoi(row[10]);
1309 team->level = atoi(row[11]);
1310 team->rank = atoi(row[12]);
1311
1312 eventlog(eventlog_level_trace,__FUNCTION__,"succesfully loaded team %u",team->teamid);
1313 cb(team);
1314 load_team_failure:
1315 ;
1316 }
1317
1318 sql->free_result(result);
1319 } else
1320 {
1321 eventlog(eventlog_level_error, __FUNCTION__, "error query db (query:\"%s\")", query);
1322 return -1;
1323 }
1324 return 0;
1325 }
1326
1327 static int sql_write_team(void *data)
1328 {
1329 char query[1024];
1330 t_sql_res *result;
1331 t_sql_row *row;
1332 t_team *team = (t_team *) data;
1333 int num;
1334
1335 if (!sql)
1336 {
1337 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1338 return -1;
1339 }
1340
1341 sprintf(query, "SELECT count(*) FROM arrangedteam WHERE teamid='%u'", team->teamid);
1342 if ((result = sql->query_res(query)) != NULL)
1343 {
1344 row = sql->fetch_row(result);
1345 if (row == NULL || row[0] == NULL)
1346 {
1347 sql->free_result(result);
1348 eventlog(eventlog_level_error, __FUNCTION__, "got NULL count");
1349 return -1;
1350 }
1351 num = atol(row[0]);
1352 sql->free_result(result);
1353 if (num < 1)
1354 sprintf(query, "INSERT INTO arrangedteam (teamid, size, clienttag, lastgame, member1, member2, member3, member4, wins,losses, xp, level, rank) VALUES('%u', '%c', '%s', '%u', '%u', '%u', '%u', '%u', '%d', '%d', '%d', '%d', '%d')", team->teamid,team->size+'0',clienttag_uint_to_str(team->clienttag),(unsigned int)team->lastgame,team->teammembers[0],team->teammembers[1],team->teammembers[2],team->teammembers[3],team->wins,team->losses,team->xp,team->level,team->rank);
1355 else
1356 sprintf(query, "UPDATE arrangedteam SET size='%c', clienttag='%s', lastgame='%u', member1='%u', member2='%u', member3='%u', member4='%u', wins='%d', losses='%d', xp='%d', level='%d', rank='%d' WHERE teamid='%u'",team->size+'0',clienttag_uint_to_str(team->clienttag),(unsigned int)team->lastgame,team->teammembers[0],team->teammembers[1],team->teammembers[2],team->teammembers[3],team->wins,team->losses,team->xp,team->level,team->rank,team->teamid);
1357 if (sql->query(query) < 0)
1358 {
1359 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1360 return -1;
1361 }
1362 } else
1363 {
1364 eventlog(eventlog_level_error, __FUNCTION__, "error trying query: \"%s\"", query);
1365 return -1;
1366 }
1367
1368 return 0;
1369 }
1370
1371 static int sql_remove_team(unsigned int teamid)
1372 {
1373 char query[1024];
1374
1375 if (!sql)
1376 {
1377 eventlog(eventlog_level_error, __FUNCTION__, "sql layer not initilized");
1378 return -1;
1379 }
1380
1381 sprintf(query, "DELETE FROM arrangedteam WHERE teamid='%u'", teamid);
1382 if (sql->query(query) != 0)
1383 return -1;
1384
1385 return 0;
1386 }
1387
1388 #endif /* WITH_SQL */

webmaster@leafok.com
ViewVC Help
Powered by ViewVC 1.3.0-beta1