add multi-rules management
[brisk.git] / web / Obj / dbase_pgsql.phh
1 <?php
2   /*
3    *  brisk - dbase_pgsql.phh
4    *
5    *  Copyright (C) 2006-2015 Matteo Nastasi
6    *                          mailto: nastasi@alternativeoutput.it
7    *                                  matteo.nastasi@milug.org
8    *                          web: http://www.alternativeoutput.it
9    *
10    * This program is free software; you can redistribute it and/or modify
11    * it under the terms of the GNU General Public License as published by
12    * the Free Software Foundation; either version 2 of the License, or
13    * (at your option) any later version.
14    *
15    * This program is distributed in the hope that it will be useful, but
16    * WITHOUT ANY WARRANTY; without even the implied warranty of
17    * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18    * General Public License for more details. You should have received a
19    * copy of the GNU General Public License along with this program; if
20    * not, write to the Free Software Foundation, Inc, 59 Temple Place -
21    * Suite 330, Boston, MA 02111-1307, USA.
22    *
23    */
24
25 require_once("${G_base}Obj/dbase_base.phh");
26
27 $escsql_from = array( "\\",   "'"   );
28 $escsql_to   = array( "\\\\", "''" );
29
30 function escsql($s)
31 {
32     GLOBAL $escsql_from, $escsql_to;
33
34     return str_replace($escsql_from, $escsql_to, $s);
35 }
36
37 class DBConn
38 {
39     static $dbcnnx = FALSE;
40     var $db = FALSE;
41
42     function DBConn()
43     {
44         $this->db = DBConn::$dbcnnx;
45     }
46
47     static function create()
48     {
49         GLOBAL $G_dbauth;
50
51         if (DBConn::$dbcnnx == FALSE) {
52             if (!(DBConn::$dbcnnx = @pg_connect ($G_dbauth, PGSQL_CONNECT_FORCE_NEW))) {
53                 return (FALSE);
54             }
55         }
56
57         $out = new DBConn();
58
59         return $out;
60     }
61
62     static function destroy()
63     {
64         if (DBConn::$dbcnnx != FALSE) {
65             $ret = pg_close(DBConn::$dbcnnx);
66             DBConn::$dbcnnx = FALSE;
67             return ($ret);
68         }
69         return TRUE;
70     }
71
72     static function recover()
73     {
74         self::destroy();
75         return (self::create());
76     }
77
78     function db()
79     {
80         return ($this->db);
81     }
82 }
83
84 class BriskDB
85 {
86     var $dbconn;
87     var $item;
88     var $item_n;
89
90     function BriskDB($dbconn)
91     {
92         $this->dbconn = $dbconn;
93     }
94
95     static function create()
96     {
97         GLOBAL $DOCUMENT_ROOT, $G_dbpfx;
98
99         $ret = FALSE;
100
101         log_main("BriskDB create:start");
102
103         do {
104             if (($dbconn = DBConn::create()) == FALSE) {
105                 break;
106             }
107
108             $ret = new BriskDB($dbconn);
109         } while (0);
110
111         return ($ret);
112     }
113
114     function query($sql)
115     {
116         if (!$this->dbconn)
117             if (($this->dbconn = DBConn::recover()) == FALSE)
118                 return FALSE;
119
120         if (($res = @pg_query($this->dbconn->db(), $sql)) == FALSE) {
121             error_log('pg_result_status: ' .  pg_result_status($res));
122             error_log('pg_connection_status: ' .  pg_connection_status($this->dbconn->db()));
123             // try to recover the connection
124             if (($this->dbconn = DBConn::recover()) == FALSE)
125                 return FALSE;
126             return (@pg_query($this->dbconn->db(), $sql));
127         }
128
129         return ($res);
130     }
131
132     function last_error()
133     {
134         return pg_last_error($this->dbconn->db);
135     }
136
137     function users_load()
138     {
139     }
140
141     function login_exists($login)
142     {
143         GLOBAL $G_dbpfx;
144
145         /* check the existence of the nick in the BriskDB */
146         log_main("login_exists: ".$login);
147
148         $user_sql = sprintf("SELECT * FROM %susers WHERE login = '%s'",
149                             $G_dbpfx, escsql($login));
150         if (($user_pg = $this->query($user_sql)) != FALSE)
151             if (pg_numrows($user_pg) == 1)
152                 return TRUE;
153
154         return FALSE;
155     }
156
157     function getrecord_bylogin($login) {
158         GLOBAL $G_dbpfx;
159
160         $user_sql = sprintf("SELECT * FROM %susers WHERE login = lower('%s') AND (type & CAST (X'%08x' as integer)) = 0;",  $G_dbpfx, escsql($login), USER_FLAG_TY_DISABLE);
161         if (($user_pg  = $this->query($user_sql)) == FALSE) {
162             return FALSE;
163         }
164         if (pg_numrows($user_pg) != 1)
165             return FALSE;
166
167         $user_obj = pg_fetch_object($user_pg, 0);
168
169         return ($user_obj);
170     }
171
172     function user_add($login, $pass, $email, $type, $disa_reas, $guar_code) {
173         GLOBAL $G_dbpfx;
174
175         $usr_sql = sprintf("INSERT INTO %susers (login, pass, email, type, disa_reas, guar_code, lintm)
176                             VALUES ('%s', '%s', '%s', %d, %d, %d, now()) RETURNING *;",
177                            $G_dbpfx, escsql(strtolower($login)), escsql($pass), escsql($email),
178                            $type, $disa_reas, $guar_code);
179
180         if (! (($usr_pg  = $this->query($usr_sql)) != FALSE && pg_affected_rows($usr_pg) == 1) ) {
181             return FALSE;
182         }
183         $usr_obj = pg_fetch_object($usr_pg, 0);
184
185         return $usr_obj;
186     }
187
188     function transaction($cmd) {
189         if ($cmd != "BEGIN" && $cmd != "COMMIT" && $cmd != "ROLLBACK")
190             return FALSE;
191
192         $trans_sql = sprintf("%s;", $cmd);
193         if (($trans_pg  = $this->query($trans_sql)) == FALSE) {
194             return FALSE;
195         }
196
197         return (TRUE);
198     }
199
200     /*
201       $laddr is native php int (32 or 64 bit)
202       if ret True is ip is free
203     */
204     function selfreg_check($laddr)
205     {
206         GLOBAL $G_dbpfx, $G_selfreg_tout, $G_selfreg_mask;
207
208         $sere_sql = sprintf("DELETE from %sselfreg_chk WHERE atime < now();", $G_dbpfx);
209         if (($sere_pg = $this->query($sere_sql)) == FALSE) {
210             return (FALSE);
211         }
212
213         $sere_sql = sprintf("SELECT * FROM %sselfreg_chk WHERE (ip & %d) = %d;",
214                             $G_dbpfx, int2four($G_selfreg_mask), int2four($laddr & $G_selfreg_mask));
215         if (($sere_pg  = $this->query($sere_sql)) == FALSE) {
216             return(FALSE);
217         }
218
219         $ret = pg_numrows($sere_pg);
220
221         if ($ret === FALSE) {
222             return(FALSE);
223         }
224         else if ($ret === 0) {
225             return(TRUE);
226         }
227         else if ($ret > 0) {
228             // already present
229             return(FALSE);
230         }
231         else {
232             // unreachable branch
233             return(FALSE);
234         }
235     }
236
237     /*
238       $laddr is native php int (32 or 64 bit)
239       if ret True is ip is free
240     */
241     function selfreg_set($laddr)
242     {
243         GLOBAL $G_dbpfx, $G_selfreg_tout, $G_selfreg_mask;
244
245         $newi_sql = sprintf("INSERT INTO %sselfreg_chk (ip, atime) VALUES (%d, now() + interval '%d seconds');",
246                             $G_dbpfx, int2four($laddr & $G_selfreg_mask), $G_selfreg_tout);
247         if (($newi_pg  = $this->query($newi_sql)) == FALSE) {
248             return(FALSE);
249         }
250         return(TRUE);
251     }
252
253     /*
254       to be able to add mail record code into the record itself I must reserve it before.
255      */
256     function mail_reserve_code() {
257         GLOBAL $G_dbpfx;
258
259         $mail_sql = sprintf("SELECT nextval('%smails_code_seq'::regclass) AS nextval;", $G_dbpfx);
260         if (($mail_pg  = $this->query($mail_sql)) == FALSE) {
261             return FALSE;
262         }
263         if (pg_numrows($mail_pg) != 1)
264             return FALSE;
265
266         $mail_obj = pg_fetch_object($mail_pg, 0);
267
268         return ($mail_obj->nextval);
269     }
270
271     function check_record_by_login_or_email($login, $email) {
272         GLOBAL $G_dbpfx;
273
274         $arr_fie = array('login', 'email');
275         $arr_val = array($login, $email);
276
277         for ($i = 0 ; $i < 2 ; $i++) {
278             $user_sql = sprintf("SELECT * FROM %susers WHERE %s = lower('%s');",
279                                 $G_dbpfx, $arr_fie[$i], escsql($arr_val[$i]));
280             if (($user_pg  = $this->query($user_sql)) == FALSE) {
281                 fprintf(STDERR, "QUERY [%s]_ FALSE", $user_sql);
282                 return (3);
283             }
284             if (pg_numrows($user_pg) == 1) {
285                 return ($i + 1);
286             }
287         }
288
289         return (0);
290     }
291
292     function getrecord_bycode($code) {
293         GLOBAL $G_dbpfx;
294
295         $user_sql = sprintf("SELECT * FROM %susers WHERE code = %d;",  $G_dbpfx, $code);
296         if (($user_pg  = $this->query($user_sql)) == FALSE) {
297             return FALSE;
298         }
299         if (pg_numrows($user_pg) != 1)
300             return FALSE;
301
302         $user_obj = pg_fetch_object($user_pg, 0);
303
304         return ($user_obj);
305     }
306
307     function user_update_login_time($code, $lintm)
308     {
309         GLOBAL $G_dbpfx;
310
311         $user_sql = sprintf("UPDATE %susers SET (lintm) = (date 'epoch' + %d * INTERVAL '1 second') WHERE code = %d;", $G_dbpfx, $lintm, $code);
312
313         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
314              return FALSE;
315         }
316
317         return TRUE;
318     }
319
320     function user_update_flag_ty($code, $type, $old_val, $old_reas, $new_val, $new_reas)
321     {
322         GLOBAL $G_dbpfx;
323
324         $user_sql = sprintf("UPDATE %susers SET (type, disa_reas)
325             = (type & ~(CAST (X'%08x' as integer)) | (CAST (X'%08x' as integer)), %d)
326             WHERE code = %d AND (type & (CAST (X'%08x' as integer)))
327                 = (CAST (X'%08x' as integer)) AND disa_reas = %d;",
328                             $G_dbpfx, $type, ($new_val ? $type : 0), $new_reas,
329                             $code, $type, ($old_val ? $type : 0), $old_reas);
330
331         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
332              return FALSE;
333         }
334
335         return TRUE;
336     }
337
338     function user_update_passwd($code, $passwd)
339     {
340         GLOBAL $G_dbpfx;
341
342         $user_sql = sprintf("UPDATE %susers SET (pass) = (md5('%s')) WHERE code = %d;",
343                             $G_dbpfx, $passwd, $code);
344
345         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
346              return FALSE;
347         }
348
349         return TRUE;
350     }
351
352     function user_prefs_update($code, $flags, $supp_comp)
353     {
354         GLOBAL $G_dbpfx;
355
356         $user_sql = sprintf("UPDATE %susers SET (type, supp_comp) = (%d, '%s') WHERE code = %d;",
357                             $G_dbpfx, $flags, escsql($supp_comp), $code);
358         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
359              return FALSE;
360         }
361
362         return TRUE;
363     }
364
365     function user_state_update($code, $flags, $disa_reas)
366     {
367         GLOBAL $G_dbpfx;
368
369         $user_sql = sprintf("UPDATE %susers SET (type, disa_reas) = (%d, %d) WHERE code = %d;",
370                             $G_dbpfx, $flags, $disa_reas, $code);
371         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
372              return FALSE;
373         }
374
375         return TRUE;
376     }
377
378     function user_tos_update($code, $tos_vers)
379     {
380         GLOBAL $G_dbpfx;
381
382         $user_sql = sprintf("UPDATE %susers SET (tos_vers) = ('%s') WHERE code = %d;",
383                             $G_dbpfx, escsql($tos_vers), $code);
384         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
385              return FALSE;
386         }
387
388         return TRUE;
389     }
390
391     /*
392       if success return a LoginDBItem object
393      */
394     function login_verify($login, $pass)
395     {
396         GLOBAL $G_dbpfx;
397
398         $ret = FALSE;
399
400         log_main("login_verify: ".$login);
401
402         //O /* check the existence of the nick in the BriskDB */
403         //O for ($i = 0 ; $i < $this->item_n ; $i++) {
404         //O log_main("login_verify: BEGIN");
405
406         if (($user_obj = $this->getrecord_bylogin($login)) == FALSE) {
407             return FALSE;
408         }
409
410         log_main("login[".$user_obj->code."]: ".$user_obj->login);
411
412         /* if it exists check for a valid challenge */
413         if (($a_sem = Challenges::lock_data(TRUE)) != FALSE) {
414             if (($chals = &Challenges::load_data()) != FALSE) {
415                 for ($e = 0 ; $e < $chals->item_n ; $e++) {
416                     log_main("challenge[".$e."]: ".$chals->item[$e]->login);
417                     if (strcmp($login, $chals->item[$e]->login) == 0) {
418                         log_main("login_verify [".$pass."] with [".md5($chals->item[$e]->token.$user_obj->pass)."]");
419
420                         if (strcmp($pass, md5($chals->item[$e]->token.$user_obj->pass)) == 0) {
421                             log_main("login_verify SUCCESS for ".$login);
422
423                             $chals->rem($login);
424                             $this->user_update_login_time($user_obj->code, time());
425                             $ret = LoginDBItem::LoginDBItemFromRecord($user_obj);
426                             break;
427                         }
428                     }
429                 } // end for ($e = 0 ...
430             }
431
432             if ($chals->ismod()) {
433                 Challenges::save_data(&$chals);
434             }
435
436             Challenges::unlock_data($a_sem);
437         }
438         //O break;
439         // O } //  if (strcasecmp($this->item[$i]->login, ...
440         //O }
441
442         return ($ret);
443     }
444
445     function getitem_bylogin($login, &$id) {
446         $ret = FALSE;
447         $id = -1;
448
449         log_main("getitem_bylogin: ".$login);
450
451         if (($user_obj = $this->getrecord_bylogin($login)) == FALSE)
452             return $ret;
453
454         $id = $user_obj->code;
455         return (LoginDBItem::LoginDBItemFromRecord($user_obj));
456     }
457
458     function getitem_bycode($code) {
459         $ret = FALSE;
460
461         log_main("getitem_bycode: ".$code);
462
463         if (($user_obj = $this->getrecord_bycode($code)) == FALSE)
464             return $ret;
465
466         return (LoginDBItem::LoginDBItemFromRecord($user_obj));
467     }
468
469     // TODO FOR DB
470     function getmail($login)
471     {
472         log_main("getmail");
473
474         if (($ret = $this->getrecord_bylogin($login)) == FALSE)
475             return FALSE;
476
477         return ($ret->email);
478     }
479
480     function addusers_from_olddb($olddb, &$cont)
481     {
482         GLOBAL $G_dbpfx;
483
484         for ($i = 0 ; $i < $olddb->count() ; $i++) {
485             $user_sql = sprintf("INSERT INTO %susers ( login, pass, email, type) VALUES ('%s', '%s', '%s', %d);",
486                                 $G_dbpfx, escsql(strtolower($olddb->item[$i]->login)), escsql($olddb->item[$i]->pass),
487                                 escsql($olddb->item[$i]->email), $olddb->item[$i]->type & USER_FLAG_TY_ALL);
488
489             if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
490                 $cont .= sprintf("ERROR IN LINE: %s\n", eschtml($user_sql));
491
492                 return FALSE;
493             }
494         }
495         return TRUE;
496     }
497
498     function getdbconn()
499     {
500         return ($this->dbconn);
501     }
502
503     // return array of array('code', 'login' [, 'first', 'last', 'tidx']) ordered by table position
504     function users_get($match_code, $with_minmaxtidx, $is_newmatch)
505     {
506         GLOBAL $G_dbpfx;
507
508         if ($is_newmatch) { // is new
509             $usr_sql = sprintf("SELECT u.code AS code, u.login AS login%s
510                                   FROM %sbin5_matches AS m, %sbin5_games AS g, %sbin5_points AS p,
511                                        %susers AS u, %sbin5_table_orders AS o
512                                   WHERE m.code = g.mcode AND g.code = p.gcode AND u.code = p.ucode
513                                        AND m.code = o.mcode AND u.code = o.ucode AND m.code = %d
514                                   GROUP BY u.code, u.login%s, o.pos
515                                   ORDER BY o.pos;",
516                                ($with_minmaxtidx ? ", min(g.tstamp) AS first, max(g.tstamp) AS last, m.tidx AS tidx" : ""),
517                                $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code,
518                                ($with_minmaxtidx ? ", m.tidx" : ""));
519         }
520         else { // is old
521             $usr_sql = sprintf("SELECT u.code AS code, u.login AS login%s
522                                   FROM %sbin5_matches AS m, %sbin5_games AS g, %sbin5_points AS p, %susers AS u
523                                   WHERE m.code = g.mcode AND g.code = p.gcode AND u.code = p.ucode AND m.code = %d
524                                   GROUP BY u.code, u.login%s;",
525                                ($with_minmaxtidx ? ", min(g.tstamp) AS first, max(g.tstamp) AS last, m.tidx AS tidx" : ""),
526                                $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code,
527                                ($with_minmaxtidx ? ", m.tidx" : ""));
528         }
529
530         if (($usr_pg  = pg_query($this->dbconn->db(), $usr_sql)) == FALSE ) {
531             log_crit(sprintf("%s::%s: pg_query usr_sql failed [%s]", __CLASS__, __FUNCTION__, $usr_sql));
532             return (FALSE);
533         }
534         $usr_n = pg_numrows($usr_pg);
535         if ($usr_n != BIN5_PLAYERS_N) {
536             log_crit(sprintf("%s::%s: wrong number of players [%s] %d", __CLASS__, __FUNCTION__, $usr_sql, $usr_n));
537             return (FALSE);
538         }
539         $users = array();
540
541         if ($with_minmaxtidx)
542             $fields = array('code', 'login', 'first', 'last', 'tidx');
543         else
544             $fields = array('code', 'login');
545
546         for ($u = 0 ; $u < $usr_n ; $u++) {
547             $usr_obj = pg_fetch_object($usr_pg, $u);
548             $users[$u] = array();
549             foreach($fields as $field) {
550                 $users[$u][$field] = $usr_obj->$field;
551             }
552         }
553         return ($users);
554     }
555
556     // out: tab->{points,points_n,old_reason}, in: tab->ttok
557     function match_continue($match_code, $table, $tidx)
558     {
559         GLOBAL $G_dbpfx;
560         $sql_ttok = escsql($table->table_token);
561
562         if (($users = $this->users_get($match_code, FALSE /*without minmaxidx*/, TRUE /*new game*/)) == FALSE) {
563             log_crit(sprintf("%s::%s: retrieve users fails", __CLASS__, __FUNCTION__));
564             return (FALSE);
565         }
566
567         $num_sql = sprintf("SELECT count(*) AS points_n FROM %sbin5_games WHERE mcode = %d;", $G_dbpfx, $match_code);
568         if (($num_pg  = $this->query($num_sql)) == FALSE || pg_numrows($num_pg) != 1) {
569             log_crit(sprintf("%s::%s: get games number fails", __CLASS__, __FUNCTION__));
570             return (FALSE);
571         }
572         $num_obj = pg_fetch_object($num_pg, 0);
573         $table->points_n = $num_obj->points_n;
574
575         // TAG: POINTS_MANAGEMENT
576         $tot_sql = sprintf("SELECT sum(p.pts * (2^g.mult)) AS pts
577                             FROM %sbin5_games AS g, %sbin5_points AS p, %susers AS u,
578                                  %sbin5_table_orders AS o
579                             WHERE g.mcode = %d AND g.code = p.gcode AND p.ucode = u.code
580                                   AND p.ucode = o.ucode AND g.mcode = o.mcode
581                             GROUP BY p.ucode, o.pos
582                             ORDER BY o.pos;",
583                            $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code);
584         if (($tot_pg  = pg_query($this->dbconn->db(), $tot_sql)) == FALSE
585             || pg_numrows($tot_pg) != BIN5_PLAYERS_N) {
586             log_crit(sprintf("%s::%s: get games totals fails", __CLASS__, __FUNCTION__));
587             return(FALSE);
588         }
589
590         $u = 0;
591         foreach ($users as $user) {
592             // TAG: POINTS_MANAGEMENT
593             $pts_sql = sprintf("SELECT p.pts AS pts, g.mult AS mult
594                                     FROM %sbin5_points as p, %sbin5_games as g
595                                     WHERE p.gcode = g.code AND g.mcode = %d AND p.ucode = %d
596                                     ORDER BY g.tstamp ASC
597                                     LIMIT %d OFFSET %d;",
598                                $G_dbpfx, $G_dbpfx, $match_code, $user['code'],
599                                MAX_POINTS,
600                                ($num_obj->points_n < MAX_POINTS ? 0 : $num_obj->points_n - MAX_POINTS));
601
602             // points of the match for each user
603             if (($pts_pg  = $this->query($pts_sql)) == FALSE) {
604                 log_crit(sprintf("%s::%s: get points fails", __CLASS__, __FUNCTION__));
605                 return (FALSE);
606             }
607             $pts_n = pg_numrows($pts_pg);
608             if ($pts_n > $table->points_n) {
609                 // inconsistent scenario number of points great than number of games
610                 log_crit(sprintf("%s::%s: number of points great than number of games", __CLASS__, __FUNCTION__));
611                 return (FALSE);
612             }
613             // TAG: POINTS_MANAGEMENT
614             for ($i = 0 , $ct = $table->points_n - $pts_n; $ct < $table->points_n ; $ct++, $i++) {
615                 $pts_obj = pg_fetch_object($pts_pg, $i);
616                 $table->points[$ct % MAX_POINTS][$u] = $pts_obj->pts * pow(2, $pts_obj->mult);
617             }
618             $tot_obj = pg_fetch_object($tot_pg, $u);
619             $table->total[$u] = $tot_obj->pts;
620
621             $u++;
622         }
623
624         $gam_sql = sprintf("SELECT * FROM %sbin5_games WHERE mcode = %d ORDER BY tstamp DESC LIMIT 1;", $G_dbpfx, $match_code);
625         if (($gam_pg  = $this->query($gam_sql)) == FALSE || pg_numrows($gam_pg) != 1) {
626             log_crit(sprintf("%s::%s: get last game fails", __CLASS__, __FUNCTION__));
627             return (FALSE);
628         }
629         $gam_obj = pg_fetch_object($gam_pg, 0);
630
631         // update matches with new ttok and table idx
632         $mtc_sql = sprintf("UPDATE %sbin5_matches SET (ttok, tidx) = ('%s', %d) WHERE code = %d RETURNING *;",
633                            $G_dbpfx, $sql_ttok, $tidx, $match_code);
634         if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_numrows($mtc_pg) != 1) {
635             log_crit(sprintf("%s::%s: update matches table failed", __CLASS__, __FUNCTION__));
636             return (FALSE);
637         }
638         $mtc_obj = pg_fetch_object($mtc_pg, 0);
639
640         $old_rules = $table->rules;
641         $rules_name = rules_id2name($mtc_obj->tcode);
642         $table->rules = new $rules_name($table);
643         unset($old_rules);
644
645         $table->old_reason = ${rules_name}::game_description($gam_obj->act, 'html', $gam_obj->mult,
646                                               $gam_obj->asta_win, ($gam_obj->asta_win != -1 ?
647                                                                    $users[$gam_obj->asta_win]['login'] : ""),
648                                               $gam_obj->friend, ($gam_obj->friend != -1 ?
649                                                                  $users[$gam_obj->friend]['login'] : ""),
650                                               $gam_obj->pnt, $gam_obj->asta_pnt, $gam_obj->tourn_pts);
651
652
653         return (TRUE);
654     }
655
656     function match_order_get(&$match_data, $match_code, $exp_num)
657     {
658         GLOBAL $G_dbpfx;
659
660         $ord_sql = sprintf("SELECT ucode FROM %sbin5_table_orders WHERE mcode = %d ORDER BY pos ASC;",
661                            $G_dbpfx, $match_code);
662
663         if (($ord_pg  = $this->query($ord_sql)) == FALSE || pg_numrows($ord_pg) != $exp_num) {
664             log_crit(sprintf("%s: fails for id or users number", __FUNCTION__));
665             return (FALSE);
666         }
667
668         $ucodes = array();
669         for ($i = 0 ; $i < $exp_num ; $i++) {
670             $ord_obj = pg_fetch_object($ord_pg, $i);
671             $ucodes[$i] = $ord_obj->ucode;
672         }
673
674         if ($match_data !== NULL) {
675             $mtdt_sql = sprintf("SELECT * FROM %sbin5_matches WHERE code = %d;",
676                                 $G_dbpfx, $match_code);
677
678             if (($mtdt_pg  = $this->query($mtdt_sql)) == FALSE || pg_numrows($mtdt_pg) != 1) {
679                 log_crit(sprintf("%s: fails retrieve match_data values [%d]", __FUNCTION__, $match_code));
680                 return (FALSE);
681             }
682
683             $mtdt_obj = pg_fetch_object($mtdt_pg, 0);
684
685             foreach (array('ttok', 'tidx', 'mult_next', 'mazzo_next', 'tcode') as $match_name) {
686                 $match_data[$match_name] = $mtdt_obj->$match_name;
687             }
688         }
689
690         return ($ucodes);
691     }
692
693     //   ttok   text UNIQUE,
694     //   tidx
695     function bin5_points_save($date, $table, $tidx, $action, $ucodes, $pts)
696     {
697         GLOBAL $G_dbpfx;
698         $sql_ttok = escsql($table->table_token);
699
700         $is_trans = FALSE;
701         $ret = FALSE;
702
703         $n = count($ucodes);
704         /* check the existence of the nick in the BriskDB */
705         log_main("bin5_points_save: ");
706
707         do {
708             if ($this->query("BEGIN") == FALSE) {
709                 break;
710             }
711             $is_trans = TRUE;
712
713             /*
714              * matches management
715              */
716             $codes_where = "";
717             $mtc_sql = sprintf("UPDATE %sbin5_matches SET (mazzo_next, mult_next) = (%d, %d) WHERE ttok = '%s' RETURNING *;",
718                                $G_dbpfx, $table->mazzo, $table->mult, $sql_ttok);
719             if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_numrows($mtc_pg) != 1) {
720
721                 // match not exists, insert it
722                 // , BIN5_TOURNAMENT_NO_DRAW
723                 $mtc_sql = sprintf("INSERT INTO %sbin5_matches (ttok, tidx, mazzo_next, mult_next, tcode) VALUES ('%s', %d, %d, %d, %d) RETURNING *;",
724                                    $G_dbpfx, $sql_ttok, $tidx, $table->mazzo, $table->mult, BIN5_TOURNAMENT_CURRENT);
725                 if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_affected_rows($mtc_pg) != 1) {
726                     log_crit(sprintf("bin5_points_save: failed at insert match [%s]", $mtc_sql));
727                     break;
728                 }
729                 $mtc_obj = pg_fetch_object($mtc_pg, 0);
730
731                 for ($i = 0 ; $i < $n ; $i++) {
732                     $ord_sql = sprintf("INSERT INTO %sbin5_table_orders (mcode, ucode, pos) VALUES (%d, %d, %d);",
733                                        $G_dbpfx, $mtc_obj->code, $ucodes[$i], $i);
734                     if (($ord_pg = $this->query($ord_sql)) == FALSE || pg_affected_rows($ord_pg) != 1 ) {
735                         log_crit(sprintf("bin5_points_save: failed at insert table order [%s]", $ord_sql));
736                         break;
737                     }
738                     $codes_where .= sprintf("%scode = %d", ($i == 0  ? "" : " OR "), $ucodes[$i]);
739                 }
740                 if ($i < $n)
741                     break;
742
743                 $cnt_sql = sprintf("UPDATE %susers SET (match_cnt, game_cnt)
744                                         = (match_cnt+1, game_cnt+1) WHERE %s;",
745                                    $G_dbpfx, $codes_where);
746                 error_log($cnt_sql);
747                 if (($cnt_pg = $this->query($cnt_sql)) == FALSE || pg_affected_rows($cnt_pg) != $n) {
748                     log_crit(sprintf("bin5_points_save: failed increment match and game [%s]", $cnt_sql));
749                     break;
750                 }
751             }
752             else {
753                 $mtc_obj = pg_fetch_object($mtc_pg,0);
754
755                 for ($i = 0 ; $i < $n ; $i++) {
756                     $codes_where .= sprintf("%scode = %d", ($i == 0 ? "" : " OR "), $ucodes[$i]);
757                 }
758                 $cnt_sql = sprintf("UPDATE %susers SET (game_cnt)
759                                         = (game_cnt+1) WHERE %s;",
760                                    $G_dbpfx, $codes_where);
761                 error_log($cnt_sql);
762                 if (($cnt_pg = $this->query($cnt_sql)) == FALSE || pg_affected_rows($cnt_pg) != $n) {
763                     log_crit(sprintf("bin5_points_save: failed increment game [%s]", $cnt_sql));
764                     break;
765                 }
766             }
767
768             /*
769              * games management
770              */
771             $gam_sql = sprintf("INSERT INTO %sbin5_games (mcode, tstamp, act, asta_pnt, pnt, asta_win, friend, mazzo, mult, tourn_pts)
772                                                VALUES (%d, to_timestamp(%d), %d, %d, %d, %d, %d, %d, %d, %d) RETURNING *;",
773                                $G_dbpfx, $mtc_obj->code, $date, $action,
774                                $table->old_asta_pnt, $table->old_pnt,
775                                $table->old_asta_win,
776                                $table->old_friend,
777                                $table->old_mazzo, $table->old_mult,
778                                $table->old_tourn_pts);
779             if (($gam_pg  = $this->query($gam_sql)) == FALSE || pg_affected_rows($gam_pg) != 1) {
780                 log_crit(sprintf("bin5_points_save: failed at insert game [%s]", $gam_sql));
781                 break;
782             }
783
784             $gam_obj = pg_fetch_object($gam_pg,0);
785
786             /*
787              * points management
788              */
789             for ($i = 0 ; $i < $n ; $i++) {
790                 /* put points */
791                 $pts_sql = sprintf("INSERT INTO %sbin5_points (gcode, ucode, pts)
792                                                VALUES (%d, %d, %d);",
793                                    $G_dbpfx, $gam_obj->code, $ucodes[$i], $pts[$i]);
794                 if (($pts_pg  = $this->query($pts_sql)) == FALSE || pg_affected_rows($pts_pg) != 1) {
795                     log_crit(sprintf("bin5_points_save: failed at insert point [%s]", $pts_sql));
796                     break;
797                 }
798             }
799             if ($i < $n)
800                 break;
801
802             if ($this->query("COMMIT") == FALSE) {
803                 break;
804             }
805
806             $is_trans = FALSE;
807
808             $table->match_id = $mtc_obj->code;
809             $ret = TRUE;
810         } while (0);
811
812         if ($is_trans)
813             $this->query("ROLLBACK");
814
815         return $ret;
816     }
817
818     function mail_add_fromitem($mail) {
819         GLOBAL $G_dbpfx;
820
821         $usr_sql = sprintf("
822 INSERT INTO %smails (code, ucode, type, tstamp, subj, body_txt, body_htm, hash)
823             VALUES (%d, %d, %d, to_timestamp(%d), '%s', '%s', '%s', '%s') RETURNING *;",
824                            $G_dbpfx, $mail->code, $mail->ucode, $mail->type, $mail->tstamp,
825                            escsql($mail->subj), escsql($mail->body_txt), escsql($mail->body_htm),
826                            ($mail->hash == NULL ? "" : escsql($mail->hash))
827                            );
828
829         if (! (($usr_pg  = $this->query($usr_sql)) != FALSE && pg_affected_rows($usr_pg) == 1) ) {
830             return FALSE;
831         }
832         $usr_obj = pg_fetch_object($usr_pg, 0);
833
834         return $usr_obj;
835     }
836
837     function mail_check($code, $type, $hash)
838     {
839         GLOBAL $G_dbpfx;
840
841         $mai_sql = sprintf("SELECT * FROM %smails WHERE code = %d AND type = %d AND hash = '%s';",
842                            $G_dbpfx, $code, $type, escsql($hash));
843         if (($mai_pg  = $this->query($mai_sql)) == FALSE || pg_numrows($mai_pg) != 1) {
844             // check failed
845             return (FALSE);
846         }
847
848         $mai_obj = pg_fetch_object($mai_pg, 0);
849         return ($mai_obj);
850     }
851
852     function mail_delete($code)
853     {
854         GLOBAL $G_dbpfx;
855
856         $mai_sql = sprintf("DELETE FROM %smails WHERE code = %d;", $G_dbpfx, $code);
857
858         if (($mai_pg = $this->query($mai_sql)) == FALSE || pg_affected_rows($mai_pg) != 1) {
859             return (FALSE);
860         }
861         return (TRUE);
862     }
863
864     function friendship_default()
865     {
866         return (array(usersnet_friend_getlabel(1) => "0",
867                       usersnet_friend_getlabel(2) => "0",
868                       usersnet_friend_getlabel(3) => "0",
869                       usersnet_friend_getlabel(4) => "0",
870                       usersnet_friend_getlabel(5) => "0"));
871     }
872
873     function usersnet_widefriend($owner, $target)
874     {
875         GLOBAL $G_dbpfx;
876
877         $widefriend = $this->friendship_default();
878
879         $wfri_sql = sprintf("SELECT * FROM %susersnet_widefriend WHERE owner = %d AND target = %d;",
880                             $G_dbpfx, $owner, $target);
881         if (($wfri_pg  = $this->query($wfri_sql)) == FALSE) {
882             return ($widefriend);
883         }
884
885         for ($i = 0 ; $i < pg_numrows($wfri_pg) ; $i++) {
886             $wfri_obj = pg_fetch_object($wfri_pg, $i);
887             $widefriend[usersnet_friend_getlabel(intval($wfri_obj->friend))] = $wfri_obj->count;
888         }
889
890         return ($widefriend);
891     }
892
893     function usersnet_wideskill($owner, $target)
894     {
895         GLOBAL $G_dbpfx;
896
897         $wideskill = "//";
898
899         $wskl_sql = sprintf("SELECT * FROM %susersnet_wideskill WHERE owner = %d AND target = %d;",
900                             $G_dbpfx, $owner, $target);
901         if (($wskl_pg  = $this->query($wskl_sql)) == FALSE) {
902             return ($wideskill);
903         }
904
905         if (pg_numrows($wskl_pg) > 0) {
906             $wskl_obj = pg_fetch_object($wskl_pg, 0);
907             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
908             // if ($wskl_obj->count >= 3)
909             $wideskill = sprintf("%3.2f", $wskl_obj->skill);
910         }
911         return ($wideskill);
912     }
913
914     function usersnet_narrowfriend($owner, $target)
915     {
916         GLOBAL $G_dbpfx;
917
918         $narrowfriend = $this->friendship_default();
919
920         $nfri_sql = sprintf("SELECT * FROM %susersnet_narrowfriend WHERE owner = %d AND target = %d;",
921                             $G_dbpfx, $owner, $target);
922         if (($nfri_pg  = $this->query($nfri_sql)) == FALSE) {
923             return $narrowfriend;
924         }
925
926         for ($i = 0 ; $i < pg_numrows($nfri_pg) ; $i++) {
927             $nfri_obj = pg_fetch_object($nfri_pg, $i);
928             $narrowfriend[usersnet_friend_getlabel(intval($nfri_obj->friend))] = $nfri_obj->count;
929         }
930         return ($narrowfriend);
931     }
932
933     function usersnet_narrowskill($owner, $target)
934     {
935         GLOBAL $G_dbpfx;
936
937         $narrowskill = "//";
938
939         $nskl_sql = sprintf("SELECT * FROM %susersnet_narrowskill WHERE owner = %d AND target = %d;",
940                             $G_dbpfx, $owner, $target);
941         if (($nskl_pg = $this->query($nskl_sql)) == FALSE) {
942             return ($narrowskill);
943         }
944
945         if (pg_numrows($nskl_pg) > 0) {
946             $nskl_obj = pg_fetch_object($nskl_pg, 0);
947             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
948             // if ($nskl_obj->count >= 3)
949             $narrowskill = sprintf("%3.2f", $nskl_obj->skill);
950         }
951         return ($narrowskill);
952     }
953
954     function usersnet_partyskill($owner, $target)
955     {
956         GLOBAL $G_dbpfx;
957
958         $partyskill = "non disponibile";
959
960         $pskl_sql = sprintf("SELECT * FROM %susersnet_party WHERE owner = %d AND target = %d;",
961                             $G_dbpfx, $owner, $target);
962         if (($pskl_pg  = $this->query($pskl_sql)) == FALSE) {
963             return ($partyskill);
964         }
965
966         if (pg_numrows($pskl_pg) > 0) {
967             $pskl_obj = pg_fetch_object($pskl_pg, 0);
968             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
969             // if ($wskl_obj->count >= 3)
970             $partyskill = sprintf("%3.2f", $pskl_obj->skill);
971         }
972         return ($partyskill);
973     }
974
975     function usersnet_bycode($owner, $target, $widefriend, $narrowfriend)
976     {
977         GLOBAL $G_dbpfx;
978         $ret = FALSE;
979
980         $net_sql = sprintf("SELECT * FROM %susersnet WHERE owner = %d AND target = %d;",
981                            $G_dbpfx, $owner, $target);
982         if (($net_pg  = $this->query($net_sql)) == FALSE)
983             return FALSE;
984
985         if (pg_numrows($net_pg) != 1)
986             return FALSE;
987
988         $net_obj = pg_fetch_object($net_pg, 0);
989
990         return (UsersNetItem::UsersNetItemFromRecord($net_obj, $widefriend, $narrowfriend));
991     }
992
993     function usersnet_default($owner, $target, $widefriend, $narrowfriend)
994     {
995         return (UsersNetItem::UsersNetItemDefaults($owner, $target, $widefriend, $narrowfriend));
996     }
997
998     function usersnet_save($owner_id, $json)
999     {
1000         GLOBAL $G_dbpfx;
1001         $ret = 99999;
1002         $trans = FALSE;
1003
1004         do {
1005             $friend = usersnet_friend_getid($json->friend);
1006
1007             $json->skill = intval($json->skill);
1008             $json->trust = intval($json->trust);
1009
1010             if ($json->skill < 1 || $json->skill > 5 ||
1011                 $json->trust < 1 || $json->trust > 5 ||
1012                 $friend == FALSE) {
1013                 $ret = 1;
1014                 break;
1015             }
1016             $this->transaction('BEGIN');
1017             $trans = TRUE;
1018
1019             if ($friend == USERSNET_FRIEND_UNKNOWN) {
1020                // try to update
1021                 $net_sql = sprintf("
1022                     DELETE FROM %susersnet
1023                         USING %susers as us
1024                         WHERE owner = %d AND us.login = '%s' AND target = us.code;",
1025                                    $G_dbpfx, $G_dbpfx,
1026                                    $owner_id, escsql(strtolower($json->login)));
1027
1028                 if (($net_pg = $this->query($net_sql)) == FALSE) {
1029                     $ret = 5;
1030                     break;
1031                 }
1032              }
1033             else { // if ($friend == USERSNET_FRIEND_UNKNOWN
1034                 // try to update
1035                 $net_sql = sprintf("
1036                     UPDATE %susersnet SET (friend, skill, trust, mtime) =
1037                         (%d, %d, %d, now())
1038                         FROM %susers as us
1039                         WHERE owner = %d AND us.login = '%s' AND target = us.code RETURNING *;",
1040                                    $G_dbpfx,
1041                                    $friend, $json->skill, $json->trust,
1042                                    $G_dbpfx,
1043                                    $owner_id, escsql(strtolower($json->login)));
1044                 if (($net_pg  = $this->query($net_sql)) == FALSE || pg_numrows($net_pg) == 0) {
1045                     $net_sql = sprintf("
1046                 INSERT INTO %susersnet SELECT %d AS owner, us.code as target,
1047                         %d as friend, %d as skill, %d as trust
1048                     FROM %susers as us WHERE us.login = '%s' RETURNING *;",
1049                                        $G_dbpfx, $owner_id,
1050                                        $friend, $json->skill, $json->trust,
1051                                        $G_dbpfx, escsql(strtolower($json->login)));
1052                     if (($net_pg  = $this->query($net_sql)) == FALSE) {
1053                         log_wr('insert query failed');
1054                         $ret = 2;
1055                         break;
1056                     }
1057                     if (pg_numrows($net_pg) != 1) {
1058                         log_wr(sprintf('insert numrow failed [%s] [%d]', $net_sql, pg_numrows($net_pg)));
1059                         $ret = 3;
1060                         break;
1061                     }
1062                 }
1063                 else {
1064                     if (pg_numrows($net_pg) != 1) {
1065                         log_wr('update numrow failed');
1066                         $ret = 4;
1067                         break;
1068                     }
1069                 }
1070             }
1071             $this->transaction('COMMIT');
1072             return (0);
1073         } while (0);
1074
1075         if ($trans)
1076             $this->transaction('ROLLBACK');
1077
1078         return ($ret);
1079     }
1080 } // End class BriskDB
1081
1082 class LoginDBOld
1083 {
1084     var $item;
1085     var $item_n;
1086
1087     function LoginDBOld($filename)
1088     {
1089         GLOBAL $DOCUMENT_ROOT;
1090         log_main("LoginDBOld create:start");
1091
1092         if (file_exists("$DOCUMENT_ROOT/Etc/".$filename)) {
1093             require("$DOCUMENT_ROOT/Etc/".$filename);
1094         }
1095         else {
1096             return (FALSE);
1097         }
1098         $this->item_n = count($this->item);
1099         log_main("LoginDBOld create:end");
1100     }
1101
1102     function count()
1103     {
1104         return ($this->item_n);
1105     }
1106
1107 } // End class LoginDBOld
1108
1109 ?>