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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (hide annotations)
Tue Jun 6 03:41:37 2006 UTC (19 years, 9 months ago) by sysadm
Branch point for: GNU, MAIN
Content type: text/x-csrc
Initial revision

1 sysadm 1.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