refactorization to manage old rules with a separated class
[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         // FIXME
632         $rules_name = "Rules_old_rules";
633         $table->old_reason = ${rules_name}::game_description($gam_obj->act, 'html', $gam_obj->mult,
634                                               $gam_obj->asta_win, ($gam_obj->asta_win != -1 ?
635                                                                    $users[$gam_obj->asta_win]['login'] : ""),
636                                               $gam_obj->friend, ($gam_obj->friend != -1 ?
637                                                                  $users[$gam_obj->friend]['login'] : ""),
638                                               $gam_obj->pnt, $gam_obj->asta_pnt, $gam_obj->tourn_pts);
639
640         // update matches with new ttok and table idx
641         $mtc_sql = sprintf("UPDATE %sbin5_matches SET (ttok, tidx) = ('%s', %d) WHERE code = %d RETURNING *;",
642                            $G_dbpfx, $sql_ttok, $tidx, $match_code);
643         if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_numrows($mtc_pg) != 1) {
644             log_crit(sprintf("%s::%s: update matches table failed", __CLASS__, __FUNCTION__));
645             return (FALSE);
646         }
647
648         return (TRUE);
649     }
650
651     function match_order_get(&$match_data, $match_code, $exp_num)
652     {
653         GLOBAL $G_dbpfx;
654
655         $ord_sql = sprintf("SELECT ucode FROM %sbin5_table_orders WHERE mcode = %d ORDER BY pos ASC;",
656                            $G_dbpfx, $match_code);
657
658         if (($ord_pg  = $this->query($ord_sql)) == FALSE || pg_numrows($ord_pg) != $exp_num) {
659             log_crit(sprintf("%s: fails for id or users number", __FUNCTION__));
660             return (FALSE);
661         }
662
663         $ucodes = array();
664         for ($i = 0 ; $i < $exp_num ; $i++) {
665             $ord_obj = pg_fetch_object($ord_pg, $i);
666             $ucodes[$i] = $ord_obj->ucode;
667         }
668
669         if ($match_data !== NULL) {
670             $mtdt_sql = sprintf("SELECT * FROM %sbin5_matches WHERE code = %d;",
671                                 $G_dbpfx, $match_code);
672
673             if (($mtdt_pg  = $this->query($mtdt_sql)) == FALSE || pg_numrows($mtdt_pg) != 1) {
674                 log_crit(sprintf("%s: fails retrieve match_data values [%d]", __FUNCTION__, $match_code));
675                 return (FALSE);
676             }
677
678             $mtdt_obj = pg_fetch_object($mtdt_pg, 0);
679
680             foreach (array('ttok', 'tidx', 'mult_next', 'mazzo_next', 'tcode') as $match_name) {
681                 $match_data[$match_name] = $mtdt_obj->$match_name;
682             }
683         }
684
685         return ($ucodes);
686     }
687
688     //   ttok   text UNIQUE,
689     //   tidx
690     function bin5_points_save($date, $table, $tidx, $action, $ucodes, $pts)
691     {
692         GLOBAL $G_dbpfx;
693         $sql_ttok = escsql($table->table_token);
694
695         $is_trans = FALSE;
696         $ret = FALSE;
697
698         $n = count($ucodes);
699         /* check the existence of the nick in the BriskDB */
700         log_main("bin5_points_save: ");
701
702         do {
703             if ($this->query("BEGIN") == FALSE) {
704                 break;
705             }
706             $is_trans = TRUE;
707
708             /*
709              * matches management
710              */
711             $codes_where = "";
712             $mtc_sql = sprintf("UPDATE %sbin5_matches SET (mazzo_next, mult_next) = (%d, %d) WHERE ttok = '%s' RETURNING *;",
713                                $G_dbpfx, $table->mazzo, $table->mult, $sql_ttok);
714             if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_numrows($mtc_pg) != 1) {
715
716                 // match not exists, insert it
717                 // , BIN5_TOURNAMENT_NO_DRAW
718                 $mtc_sql = sprintf("INSERT INTO %sbin5_matches (ttok, tidx, mazzo_next, mult_next, tcode) VALUES ('%s', %d, %d, %d, %d) RETURNING *;",
719                                    $G_dbpfx, $sql_ttok, $tidx, $table->mazzo, $table->mult, BIN5_TOURNAMENT_OLDRULES);
720                 if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_affected_rows($mtc_pg) != 1) {
721                     log_crit(sprintf("bin5_points_save: failed at insert match [%s]", $mtc_sql));
722                     break;
723                 }
724                 $mtc_obj = pg_fetch_object($mtc_pg, 0);
725
726                 for ($i = 0 ; $i < $n ; $i++) {
727                     $ord_sql = sprintf("INSERT INTO %sbin5_table_orders (mcode, ucode, pos) VALUES (%d, %d, %d);",
728                                        $G_dbpfx, $mtc_obj->code, $ucodes[$i], $i);
729                     if (($ord_pg = $this->query($ord_sql)) == FALSE || pg_affected_rows($ord_pg) != 1 ) {
730                         log_crit(sprintf("bin5_points_save: failed at insert table order [%s]", $ord_sql));
731                         break;
732                     }
733                     $codes_where .= sprintf("%scode = %d", ($i == 0  ? "" : " OR "), $ucodes[$i]);
734                 }
735                 if ($i < $n)
736                     break;
737
738                 $cnt_sql = sprintf("UPDATE %susers SET (match_cnt, game_cnt)
739                                         = (match_cnt+1, game_cnt+1) WHERE %s;",
740                                    $G_dbpfx, $codes_where);
741                 error_log($cnt_sql);
742                 if (($cnt_pg = $this->query($cnt_sql)) == FALSE || pg_affected_rows($cnt_pg) != $n) {
743                     log_crit(sprintf("bin5_points_save: failed increment match and game [%s]", $cnt_sql));
744                     break;
745                 }
746             }
747             else {
748                 $mtc_obj = pg_fetch_object($mtc_pg,0);
749
750                 for ($i = 0 ; $i < $n ; $i++) {
751                     $codes_where .= sprintf("%scode = %d", ($i == 0 ? "" : " OR "), $ucodes[$i]);
752                 }
753                 $cnt_sql = sprintf("UPDATE %susers SET (game_cnt)
754                                         = (game_cnt+1) WHERE %s;",
755                                    $G_dbpfx, $codes_where);
756                 error_log($cnt_sql);
757                 if (($cnt_pg = $this->query($cnt_sql)) == FALSE || pg_affected_rows($cnt_pg) != $n) {
758                     log_crit(sprintf("bin5_points_save: failed increment game [%s]", $cnt_sql));
759                     break;
760                 }
761             }
762
763             /*
764              * games management
765              */
766             $gam_sql = sprintf("INSERT INTO %sbin5_games (mcode, tstamp, act, asta_pnt, pnt, asta_win, friend, mazzo, mult, tourn_pts)
767                                                VALUES (%d, to_timestamp(%d), %d, %d, %d, %d, %d, %d, %d, %d) RETURNING *;",
768                                $G_dbpfx, $mtc_obj->code, $date, $action,
769                                $table->old_asta_pnt, $table->old_pnt,
770                                $table->old_asta_win,
771                                $table->old_friend,
772                                $table->old_mazzo, $table->old_mult,
773                                $table->old_tourn_pts);
774             if (($gam_pg  = $this->query($gam_sql)) == FALSE || pg_affected_rows($gam_pg) != 1) {
775                 log_crit(sprintf("bin5_points_save: failed at insert game [%s]", $gam_sql));
776                 break;
777             }
778
779             $gam_obj = pg_fetch_object($gam_pg,0);
780
781             /*
782              * points management
783              */
784             for ($i = 0 ; $i < $n ; $i++) {
785                 /* put points */
786                 $pts_sql = sprintf("INSERT INTO %sbin5_points (gcode, ucode, pts)
787                                                VALUES (%d, %d, %d);",
788                                    $G_dbpfx, $gam_obj->code, $ucodes[$i], $pts[$i]);
789                 if (($pts_pg  = $this->query($pts_sql)) == FALSE || pg_affected_rows($pts_pg) != 1) {
790                     log_crit(sprintf("bin5_points_save: failed at insert point [%s]", $pts_sql));
791                     break;
792                 }
793             }
794             if ($i < $n)
795                 break;
796
797             if ($this->query("COMMIT") == FALSE) {
798                 break;
799             }
800
801             $is_trans = FALSE;
802
803             $table->match_id = $mtc_obj->code;
804             $ret = TRUE;
805         } while (0);
806
807         if ($is_trans)
808             $this->query("ROLLBACK");
809
810         return $ret;
811     }
812
813     function mail_add_fromitem($mail) {
814         GLOBAL $G_dbpfx;
815
816         $usr_sql = sprintf("
817 INSERT INTO %smails (code, ucode, type, tstamp, subj, body_txt, body_htm, hash)
818             VALUES (%d, %d, %d, to_timestamp(%d), '%s', '%s', '%s', '%s') RETURNING *;",
819                            $G_dbpfx, $mail->code, $mail->ucode, $mail->type, $mail->tstamp,
820                            escsql($mail->subj), escsql($mail->body_txt), escsql($mail->body_htm),
821                            ($mail->hash == NULL ? "" : escsql($mail->hash))
822                            );
823
824         if (! (($usr_pg  = $this->query($usr_sql)) != FALSE && pg_affected_rows($usr_pg) == 1) ) {
825             return FALSE;
826         }
827         $usr_obj = pg_fetch_object($usr_pg, 0);
828
829         return $usr_obj;
830     }
831
832     function mail_check($code, $type, $hash)
833     {
834         GLOBAL $G_dbpfx;
835
836         $mai_sql = sprintf("SELECT * FROM %smails WHERE code = %d AND type = %d AND hash = '%s';",
837                            $G_dbpfx, $code, $type, escsql($hash));
838         if (($mai_pg  = $this->query($mai_sql)) == FALSE || pg_numrows($mai_pg) != 1) {
839             // check failed
840             return (FALSE);
841         }
842
843         $mai_obj = pg_fetch_object($mai_pg, 0);
844         return ($mai_obj);
845     }
846
847     function mail_delete($code)
848     {
849         GLOBAL $G_dbpfx;
850
851         $mai_sql = sprintf("DELETE FROM %smails WHERE code = %d;", $G_dbpfx, $code);
852
853         if (($mai_pg = $this->query($mai_sql)) == FALSE || pg_affected_rows($mai_pg) != 1) {
854             return (FALSE);
855         }
856         return (TRUE);
857     }
858
859     function friendship_default()
860     {
861         return (array(usersnet_friend_getlabel(1) => "0",
862                       usersnet_friend_getlabel(2) => "0",
863                       usersnet_friend_getlabel(3) => "0",
864                       usersnet_friend_getlabel(4) => "0",
865                       usersnet_friend_getlabel(5) => "0"));
866     }
867
868     function usersnet_widefriend($owner, $target)
869     {
870         GLOBAL $G_dbpfx;
871
872         $widefriend = $this->friendship_default();
873
874         $wfri_sql = sprintf("SELECT * FROM %susersnet_widefriend WHERE owner = %d AND target = %d;",
875                             $G_dbpfx, $owner, $target);
876         if (($wfri_pg  = $this->query($wfri_sql)) == FALSE) {
877             return ($widefriend);
878         }
879
880         for ($i = 0 ; $i < pg_numrows($wfri_pg) ; $i++) {
881             $wfri_obj = pg_fetch_object($wfri_pg, $i);
882             $widefriend[usersnet_friend_getlabel(intval($wfri_obj->friend))] = $wfri_obj->count;
883         }
884
885         return ($widefriend);
886     }
887
888     function usersnet_wideskill($owner, $target)
889     {
890         GLOBAL $G_dbpfx;
891
892         $wideskill = "//";
893
894         $wskl_sql = sprintf("SELECT * FROM %susersnet_wideskill WHERE owner = %d AND target = %d;",
895                             $G_dbpfx, $owner, $target);
896         if (($wskl_pg  = $this->query($wskl_sql)) == FALSE) {
897             return ($wideskill);
898         }
899
900         if (pg_numrows($wskl_pg) > 0) {
901             $wskl_obj = pg_fetch_object($wskl_pg, 0);
902             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
903             // if ($wskl_obj->count >= 3)
904             $wideskill = sprintf("%3.2f", $wskl_obj->skill);
905         }
906         return ($wideskill);
907     }
908
909     function usersnet_narrowfriend($owner, $target)
910     {
911         GLOBAL $G_dbpfx;
912
913         $narrowfriend = $this->friendship_default();
914
915         $nfri_sql = sprintf("SELECT * FROM %susersnet_narrowfriend WHERE owner = %d AND target = %d;",
916                             $G_dbpfx, $owner, $target);
917         if (($nfri_pg  = $this->query($nfri_sql)) == FALSE) {
918             return $narrowfriend;
919         }
920
921         for ($i = 0 ; $i < pg_numrows($nfri_pg) ; $i++) {
922             $nfri_obj = pg_fetch_object($nfri_pg, $i);
923             $narrowfriend[usersnet_friend_getlabel(intval($nfri_obj->friend))] = $nfri_obj->count;
924         }
925         return ($narrowfriend);
926     }
927
928     function usersnet_narrowskill($owner, $target)
929     {
930         GLOBAL $G_dbpfx;
931
932         $narrowskill = "//";
933
934         $nskl_sql = sprintf("SELECT * FROM %susersnet_narrowskill WHERE owner = %d AND target = %d;",
935                             $G_dbpfx, $owner, $target);
936         if (($nskl_pg = $this->query($nskl_sql)) == FALSE) {
937             return ($narrowskill);
938         }
939
940         if (pg_numrows($nskl_pg) > 0) {
941             $nskl_obj = pg_fetch_object($nskl_pg, 0);
942             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
943             // if ($nskl_obj->count >= 3)
944             $narrowskill = sprintf("%3.2f", $nskl_obj->skill);
945         }
946         return ($narrowskill);
947     }
948
949     function usersnet_partyskill($owner, $target)
950     {
951         GLOBAL $G_dbpfx;
952
953         $partyskill = "non disponibile";
954
955         $pskl_sql = sprintf("SELECT * FROM %susersnet_party WHERE owner = %d AND target = %d;",
956                             $G_dbpfx, $owner, $target);
957         if (($pskl_pg  = $this->query($pskl_sql)) == FALSE) {
958             return ($partyskill);
959         }
960
961         if (pg_numrows($pskl_pg) > 0) {
962             $pskl_obj = pg_fetch_object($pskl_pg, 0);
963             // TODO: UNCOMMENT IF THE NETWORK WORKS VERY WELL
964             // if ($wskl_obj->count >= 3)
965             $partyskill = sprintf("%3.2f", $pskl_obj->skill);
966         }
967         return ($partyskill);
968     }
969
970     function usersnet_bycode($owner, $target, $widefriend, $narrowfriend)
971     {
972         GLOBAL $G_dbpfx;
973         $ret = FALSE;
974
975         $net_sql = sprintf("SELECT * FROM %susersnet WHERE owner = %d AND target = %d;",
976                            $G_dbpfx, $owner, $target);
977         if (($net_pg  = $this->query($net_sql)) == FALSE)
978             return FALSE;
979
980         if (pg_numrows($net_pg) != 1)
981             return FALSE;
982
983         $net_obj = pg_fetch_object($net_pg, 0);
984
985         return (UsersNetItem::UsersNetItemFromRecord($net_obj, $widefriend, $narrowfriend));
986     }
987
988     function usersnet_default($owner, $target, $widefriend, $narrowfriend)
989     {
990         return (UsersNetItem::UsersNetItemDefaults($owner, $target, $widefriend, $narrowfriend));
991     }
992
993     function usersnet_save($owner_id, $json)
994     {
995         GLOBAL $G_dbpfx;
996         $ret = 99999;
997         $trans = FALSE;
998
999         do {
1000             $friend = usersnet_friend_getid($json->friend);
1001
1002             $json->skill = intval($json->skill);
1003             $json->trust = intval($json->trust);
1004
1005             if ($json->skill < 1 || $json->skill > 5 ||
1006                 $json->trust < 1 || $json->trust > 5 ||
1007                 $friend == FALSE) {
1008                 $ret = 1;
1009                 break;
1010             }
1011             $this->transaction('BEGIN');
1012             $trans = TRUE;
1013
1014             if ($friend == USERSNET_FRIEND_UNKNOWN) {
1015                // try to update
1016                 $net_sql = sprintf("
1017                     DELETE FROM %susersnet
1018                         USING %susers as us
1019                         WHERE owner = %d AND us.login = '%s' AND target = us.code;",
1020                                    $G_dbpfx, $G_dbpfx,
1021                                    $owner_id, escsql(strtolower($json->login)));
1022
1023                 if (($net_pg = $this->query($net_sql)) == FALSE) {
1024                     $ret = 5;
1025                     break;
1026                 }
1027              }
1028             else { // if ($friend == USERSNET_FRIEND_UNKNOWN
1029                 // try to update
1030                 $net_sql = sprintf("
1031                     UPDATE %susersnet SET (friend, skill, trust, mtime) =
1032                         (%d, %d, %d, now())
1033                         FROM %susers as us
1034                         WHERE owner = %d AND us.login = '%s' AND target = us.code RETURNING *;",
1035                                    $G_dbpfx,
1036                                    $friend, $json->skill, $json->trust,
1037                                    $G_dbpfx,
1038                                    $owner_id, escsql(strtolower($json->login)));
1039                 if (($net_pg  = $this->query($net_sql)) == FALSE || pg_numrows($net_pg) == 0) {
1040                     $net_sql = sprintf("
1041                 INSERT INTO %susersnet SELECT %d AS owner, us.code as target,
1042                         %d as friend, %d as skill, %d as trust
1043                     FROM %susers as us WHERE us.login = '%s' RETURNING *;",
1044                                        $G_dbpfx, $owner_id,
1045                                        $friend, $json->skill, $json->trust,
1046                                        $G_dbpfx, escsql(strtolower($json->login)));
1047                     if (($net_pg  = $this->query($net_sql)) == FALSE) {
1048                         log_wr('insert query failed');
1049                         $ret = 2;
1050                         break;
1051                     }
1052                     if (pg_numrows($net_pg) != 1) {
1053                         log_wr(sprintf('insert numrow failed [%s] [%d]', $net_sql, pg_numrows($net_pg)));
1054                         $ret = 3;
1055                         break;
1056                     }
1057                 }
1058                 else {
1059                     if (pg_numrows($net_pg) != 1) {
1060                         log_wr('update numrow failed');
1061                         $ret = 4;
1062                         break;
1063                     }
1064                 }
1065             }
1066             $this->transaction('COMMIT');
1067             return (0);
1068         } while (0);
1069
1070         if ($trans)
1071             $this->transaction('ROLLBACK');
1072
1073         return ($ret);
1074     }
1075 } // End class BriskDB
1076
1077 class LoginDBOld
1078 {
1079     var $item;
1080     var $item_n;
1081
1082     function LoginDBOld($filename)
1083     {
1084         GLOBAL $DOCUMENT_ROOT;
1085         log_main("LoginDBOld create:start");
1086
1087         if (file_exists("$DOCUMENT_ROOT/Etc/".$filename)) {
1088             require("$DOCUMENT_ROOT/Etc/".$filename);
1089         }
1090         else {
1091             return (FALSE);
1092         }
1093         $this->item_n = count($this->item);
1094         log_main("LoginDBOld create:end");
1095     }
1096
1097     function count()
1098     {
1099         return ($this->item_n);
1100     }
1101
1102 } // End class LoginDBOld
1103
1104 ?>