BUGFIX: fixed previous commit about sending mail in utf-8
[e-DoKo.git] / include / functions.php
1 <?php
2 /* Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Arun Persaud <arun@nubati.net>
3  *
4  *   This file is part of e-DoKo.
5  *
6  *   e-DoKo is free software: you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation, either version 3 of the License, or
9  *   (at your option) any later version.
10  *
11  *   e-DoKo is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with e-DoKo.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 /* make sure that we are not called from outside the scripts,
22  * use a variable defined in config.php to check this
23  */
24 if(!isset($HOST))
25   exit;
26
27 function config_check()
28 {
29   global $EmailName,$EMAIL_REPLY,$ADMIN_NAME,$ADMIN_EMAIL,$DB_work;
30
31   /* check if some variables are set in the config file, else set defaults */
32   if(!isset($EmailName))
33     $EmailName='[DoKo] ';
34   if(isset($EMAIL_REPLY))
35     {
36       ini_set('sendmail_from',$EMAIL_REPLY);
37     }
38   if(!isset($ADMIN_NAME))
39     {
40       output_header();
41       echo '<h1>Setup not completed</h1>';
42       echo 'You need to set $ADMIN_NAME in config.php.';
43       output_footer();
44       exit();
45     }
46   if(!isset($ADMIN_EMAIL))
47     {
48       output_header();
49       echo '<h1>Setup not completed</h1>';
50       echo 'You need to set $ADMIN_EMAIL in config.php. '.
51         'If something goes wrong an email will be send to this address.';
52       output_footer();
53       exit();
54     }
55   if(!isset($DB_work))
56     {
57       output_header();
58       echo '<h1>Setup not completed</h1>';
59       echo 'You need to set $DB_work in config.php. '.
60         'If this is set to anything else than 0, the game will be suspended and one can work safely on the database. '.
61         'A message will be displayed that it will probably take about N minutes, with N being the number $DB_work is set to. '.
62         'The default should be 0 for the game to work.';
63       output_footer();
64       exit();
65     }
66   if($DB_work)
67     {
68       output_header();
69       echo '<div class="WIP">'.
70         _("Working on some aspect of e-DoKo... This will probably take max. $DB_work minutes. It could be over in a few seconds too though ;)").
71         '</div>';
72       output_footer();
73       exit();
74     }
75
76   return;
77 }
78
79 /* define possible status for email subsjects */
80 define("GAME_CANCELED",         0);
81 define("GAME_CANCELED_POVERTY", 1);
82 define("GAME_CANCELED_TIMEOUT", 2);
83 define("GAME_YOUR_TURN",        3);
84 define("GAME_READY",            4);
85 define("GAME_POVERTY",          5);
86 define("GAME_DPOVERTY",         6);
87 define("GAME_OVER",             7);
88 define("GAME_RECOVERY",         8);
89 define("GAME_REMINDER",         9);
90 define("GAME_NEW",             10);
91
92 /* define possible status for showing cards */
93
94 define("CARDS_EMPTY",       0); /* show player's hand*/
95 define("CARDS_SHOW",        1); /* show player's hand*/
96 define("CARDS_MYTURN",      2); /* show radiobuttons for cards that can be played*/
97 define("CARDS_EXCHANGE",    3); /* do we need to return cards to our partner in poverty?*/
98 define("CARDS_GAMEOVER_ME", 4); /* show all cards from everyone*/
99 define("CARDS_GAMEOVER",    5); /* show all cards from everyone (looking at someone else's game)*/
100
101  /*   cards_status: SHOW      show our hand
102  *                 MYTURN    show radiobutton for cards that can be played
103  *                 EXCHANGE  do we need to return cards to our partner in poverty?
104  *                 GAMEOVER  show all cards from everyone
105  */
106
107 function mymail($uid,$gameid=0,$type,$message)
108 {
109   global $EmailName,$WIKI,$PREF;
110
111   /* uid can be either a single uid or an array, convert everything to
112    *  an array, so that we can loop over it */
113   if(!is_array($uid))
114     {
115       $to_uid=$uid;
116       $uid = array();
117       $uid[]=$to_uid;
118     }
119
120   foreach($uid as $user)
121     {
122       /* do we send the email right away or save it in the database? */
123       $send_now = 1;
124
125       $name = DB_get_name('userid',$user);
126       $To   = DB_get_email('userid',$user);
127
128       /* check if user wants email right away or if we should save it in
129        * the database for later delivery
130        */
131
132       $uidPREF = DB_get_PREF($user);
133       if( $uidPREF['digest'] != 'digest-off' )
134         $send_now = 0;
135       /* use local language */
136       set_language($uidPREF['language']);
137
138       $header  = sprintf(_('Hello %s'),$name);
139       $header .= "\n\n";
140
141       /* add standard header and footer */
142       $subject = "$EmailName ";
143       if($gameid)
144         $game = DB_format_gameid($gameid);
145       else
146         $game = '';
147
148       switch($type)
149         {
150         case GAME_CANCELED:
151           $subject.=sprintf(_('Game %s canceled'),$game);
152           break;
153         case GAME_CANCELED_POVERTY:
154           $subject.=sprintf(_('Game %s canceled (poverty not resolved)'),$game);
155           break;
156         case GAME_CANCELED_TIMEOUT:
157           $subject.=sprintf(_('Game %s canceled (timed out)'),$game);
158           break;
159         case GAME_YOUR_TURN:
160           $subject.=sprintf(_('A card has been played in game %s'),$game);
161           break;
162         case GAME_READY:
163           $subject.=sprintf(_('Ready, set, go... (game %s)'),$game);
164           break;
165         case GAME_POVERTY:
166           $subject.=sprintf(_('Poverty (game %s)'),$game);
167           break;
168         case GAME_DPOVERTY:
169           $subject.=sprintf(_('Double poverty (game %s)'),$game);
170           break;
171         case GAME_OVER:
172           $subject.=sprintf(_('Game over (game %s)'),$game);
173           break;
174         case GAME_RECOVERY:
175           $subject.=_('Recovery');
176           break;
177         case GAME_REMINDER:
178           $subject.=sprintf(_("Reminder: game %s it's your turn"),$game);
179           break;
180         case GAME_NEW:
181           $subject.=sprintf(_('You are invited to a game of DoKo (game %s)'),$game);
182           break;
183         default:
184           $subject.=sprintf(_('Problem with email, contact admin (errorcode %d)'),$gameid);
185         }
186
187       /* standard goodbye */
188       $footer  = "\n"._('Have a nice day')."\n   "._('your E-Doko service department').
189         "\n\n".
190         "-- \n".
191         _('You can change your mail delivery mode in the preference menu.').
192         "\n".
193         _('web').': http://doko.nubati.net   '.
194         _('help, bugs, etc.').": $WIKI";
195
196       if($send_now)
197         sendmail($To,$subject,$header.$message.$footer);
198       else
199         {
200           /* store email in database */
201           DB_digest_insert_email($To,$message,$type,$gameid);
202         }
203     }
204
205   /* reset language to original user*/
206   set_language($PREF['language']);
207
208   return;
209 }
210
211 function sendmail($To,$Subject,$message)
212 {
213   /* this function sends the mail or outputs to the screen in case of debugging */
214   global $debug,$EMAIL_REPLY;
215
216   $header = "";
217
218   if(isset($EMAIL_REPLY))
219     $header .= "From: e-DoKo daemon <$EMAIL_REPLY>\r\n";
220
221   $header .= "Content-Type: text/plain; charset = \"UTF-8\";\r\n";
222   $header .= "Content-Transfer-Encoding: 8bit\r\n";
223   $header .= "\r\n";
224
225   if($debug)
226     {
227       /* display email on screen,
228        * change txt -> html
229        */
230       $message = str_replace("\n","<br />\n",$message);
231       $message = preg_replace("#(\w+://[^<>\s]+[\w/]*)#",
232                               "<a href=\"$1\">$1</a>", $message);
233
234       echo "<br />To: $To<br />";
235       echo $header."<br />";
236       echo "Subject: $Subject <br />$message<br />\n";
237     }
238   else
239     mail($To,$Subject,$message,$header);
240
241   return;
242 }
243
244 function myisset()
245 {
246   /* returns 1 if all names passed as args are defined by a GET or POST statement,
247    * else return 0
248    */
249
250   $ok   = 1;
251   $args = func_get_args();
252
253   foreach($args as $arg)
254     {
255       $ok = $ok * isset($_REQUEST[$arg]);
256       /*echo "$arg: ok = $ok <br />";
257        */
258     }
259   return $ok;
260 }
261
262 function myerror($message)
263 {
264   echo "<span class=\"error\">".htmlspecialchars($message)."</span>\n";
265   sendmail($ADMIN_EMAIL,$EmailName." Error in Code",$message);
266   return;
267 }
268
269 function pos_array($c,$arr)
270 {
271   $ret = 0;
272
273   $i   = 0;
274   foreach($arr as $a)
275     {
276       $i++;
277       if($a == $c)
278         {
279           $ret = $i;
280           break;
281         }
282     }
283   return $ret;
284 }
285
286 function is_trump($c)
287 {
288   global $CARDS;
289
290   if(in_array($c,$CARDS["trump"]))
291     return 1;
292   else
293     return 0;
294 }
295
296 function is_same_suite($c1,$c2)
297 {
298   global $CARDS;
299
300   if(in_array($c1,$CARDS["trump"]   ) && in_array($c2,$CARDS["trump"]   ) ) return 1;
301   if(in_array($c1,$CARDS["clubs"]   ) && in_array($c2,$CARDS["clubs"]   ) ) return 1;
302   if(in_array($c1,$CARDS["hearts"]  ) && in_array($c2,$CARDS["hearts"]  ) ) return 1;
303   if(in_array($c1,$CARDS["spades"]  ) && in_array($c2,$CARDS["spades"]  ) ) return 1;
304   if(in_array($c1,$CARDS["diamonds"]) && in_array($c2,$CARDS["diamonds"]) ) return 1;
305
306   return 0;
307 }
308
309 function compare_cards($a,$b,$game)
310 {
311   /* if "a" is higher than "b" return 1, else 0, "a" being the card first played */
312
313   global $CARDS;
314   global $RULES;
315   global $GAME;
316
317   /* first map all cards to the odd number,
318    * this insure that the first card wins the trick
319    * if they are the same card
320    */
321   if( $a/2 - (int)($a/2) != 0.5)
322     $a--;
323   if( $b/2 - (int)($b/2) != 0.5)
324     $b--;
325
326   /* check for schweinchen and ten of hearts*/
327   switch($game)
328     {
329     case "normal":
330     case "silent":
331     case "trump":
332       if($RULES['schweinchen']=='both' && $GAME['schweinchen-who'])
333         {
334           if($a == 19 || $a == 20 )
335             return 1;
336           if($b == 19 || $b == 20 )
337             return 0;
338         }
339       else if($RULES['schweinchen']=='second' && $GAME['schweinchen-second'])
340         {
341           if($a == 19 || $a == 20 )
342             return 1;
343           if($b == 19 || $b == 20 )
344             return 0;
345         }
346       else if($RULES['schweinchen']=='secondaftercall' && $GAME['schweinchen-who'] && $GAME['schweinchen-second'] )
347         {
348           /* check if a call was made either by the player or his partner. If so activate Schweinchen rule. */
349           if(DB_get_call_by_hash($GAME['schweinchen-who']) || DB_get_partner_call_by_hash($GAME['schweinchen-who']) )
350             {
351               if($a == 19 || $a == 20 )
352                 return 1;
353               if($b == 19 || $b == 20 )
354                 return 0;
355             }
356           /* if not, do nothing and the foxes are just handeled as normal trump */
357         }
358         ;
359     case "heart":
360     case "spade":
361     case "club":
362       /* check for ten of hearts rule */
363       if($RULES["dullen"]=="secondwins")
364         if($a==1 && $b==1) /* both 10 of hearts */
365           return 0;        /* second one wins.*/
366     case "trumpless":
367     case "jack":
368     case "queen":
369       /* no special cases here */
370     }
371
372   /* normal case */
373   if(is_trump($a) && is_trump($b) && $a<=$b)
374     return 1;
375   else if(is_trump($a) && is_trump($b) )
376     return 0;
377   else
378     { /*$a is not a trump */
379       if(is_trump($b))
380         return 0;
381       else
382         { /* both no trump */
383
384           /* both clubs? */
385           $posA = pos_array($a,$CARDS["clubs"]);
386           $posB = pos_array($b,$CARDS["clubs"]);
387           if($posA && $posB)
388             if($posA <= $posB)
389               return 1;
390             else
391               return 0;
392
393           /* both spades? */
394           $posA = pos_array($a,$CARDS["spades"]);
395           $posB = pos_array($b,$CARDS["spades"]);
396           if($posA && $posB)
397             if($posA <= $posB)
398               return 1;
399             else
400               return 0;
401
402           /* both hearts? */
403           $posA = pos_array($a,$CARDS["hearts"]);
404           $posB = pos_array($b,$CARDS["hearts"]);
405           if($posA && $posB)
406             if($posA <= $posB)
407               return 1;
408             else
409               return 0;
410
411           /* both diamonds? */
412           $posA = pos_array($a,$CARDS["diamonds"]);
413           $posB = pos_array($b,$CARDS["diamonds"]);
414           if($posA && $posB)
415             if($posA <= $posB)
416               return 1;
417             else
418               return 0;
419
420           /* not the same suit and no trump: a wins */
421           return 1;
422         }
423     }
424 }
425
426 function get_winner($p,$mode)
427 {
428   /* get all 4 cards played in a trick, in the order they are played */
429   $tmp = $p[1];
430   $c1    = $tmp["card"];
431   $c1pos = $tmp["pos"];
432
433   $tmp = $p[2];
434   $c2    = $tmp["card"];
435   $c2pos = $tmp["pos"];
436
437   $tmp = $p[3];
438   $c3    = $tmp["card"];
439   $c3pos = $tmp["pos"];
440
441   $tmp = $p[4];
442   $c4    = $tmp["card"];
443   $c4pos = $tmp["pos"];
444
445   /* first card is better than all the rest */
446   if( compare_cards($c1,$c2,$mode) && compare_cards($c1,$c3,$mode) && compare_cards($c1,$c4,$mode) )
447     return $c1pos;
448
449   /* second card is better than first and better than the rest */
450   if( !compare_cards($c1,$c2,$mode) &&  compare_cards($c2,$c3,$mode) && compare_cards($c2,$c4,$mode) )
451     return $c2pos;
452
453   /* third card is better than first card and better than last */
454   if( !compare_cards($c1,$c3,$mode) &&  compare_cards($c3,$c4,$mode) )
455     /* if second card is better than first, third card needs to be even better */
456     if( !compare_cards($c1,$c2,$mode) && !compare_cards($c2,$c3,$mode) )
457       return $c3pos;
458     /* second is worse than first, e.g. not following suite */
459     else if (compare_cards($c1,$c2,$mode) )
460       return $c3pos;
461
462   /* non of the above */
463   return $c4pos;
464 }
465
466 function count_nines($cards)
467 {
468   $nines = 0;
469
470   foreach($cards as $c)
471     {
472       if($c == "25" || $c == "26") $nines++;
473       else if($c == "33" || $c == "34") $nines++;
474       else if($c == "41" || $c == "42") $nines++;
475       else if($c == "47" || $c == "48") $nines++;
476     }
477
478   return $nines;
479 }
480
481 function check_wedding($cards)
482 {
483
484   if( in_array("3",$cards) && in_array("4",$cards) )
485     return 1;
486
487   return 0;
488 }
489
490 function count_trump($cards,$status='pregame')
491 {
492   global $RULES;
493
494   $trump = 0;
495
496   /* count each trump, including the foxes, since this is used to determine poverty status */
497   foreach($cards as $c)
498     if( (int)($c) <27)
499       $trump++;
500
501   /* In case we really want to know the amount of trump, we can use the status variable.
502    * This is needed for example to figure out what icon to display on the table in case of
503    * trump given back in poverty */
504   if($status=='all') return $trump;
505
506   /* normally foxes don't count as trump, so we substract them here
507    * in case someone has schweinchen, one or two of them should count as trump
508    * though, so we need to add one trump for those cases */
509
510   /* subtract foxes */
511   if( in_array("19",$cards))
512     $trump--;
513   if( in_array("20",$cards) )
514     $trump--;
515
516   /* handle case where player has schweinchen */
517   if( in_array("19",$cards) && in_array("20",$cards) )
518     switch($RULES["schweinchen"])
519       {
520       case "both":
521         /* add two, in case the player has both foxes (schweinchen) */
522         $trump++;
523         $trump++;
524         break;
525       case "second":
526       case "secondaftercall":
527         /* add one, in case the player has both foxes (schweinchen) */
528         $trump++;
529         break;
530       case "none":
531         break;
532       }
533
534   return $trump;
535 }
536
537 function check_low_trump($cards)
538 {
539   global $RULES;
540
541   if($RULES['lowtrump']=='none')
542     return 0;
543
544   /* check if we have low trump */
545
546   $lowtrump=1;
547   foreach($cards as $card)
548     {
549       /* card a trump, but not a diamond? */
550       if( $card<19 )
551          $lowtrump=0;
552     }
553
554   /* handle case where player has schweinchen */
555   if( in_array("19",$cards) && in_array("20",$cards) )
556     switch($RULES["schweinchen"])
557       {
558       case "both":
559       case "second":
560       case "secondaftercall":
561         $lowtrump=0;
562         break;
563       case "none":
564         break;
565       }
566
567   return $lowtrump;
568 }
569
570 function  create_array_of_random_numbers($useridA,$useridB,$useridC,$useridD)
571 {
572   global $debug;
573
574   $r = array();
575
576   if($debug)
577     {
578       /* fix the hands; makes debugging easier; the following hands have lots of sicknesses,
579        * to make testing easier
580        */
581       $r[ 0]=1;     $r[12]=47;   $r[24]=13;       $r[36]=37;
582       $r[ 1]=2;     $r[13]=23;   $r[25]=14;       $r[37]=38;
583       $r[ 2]=3;     $r[14]=27;   $r[26]=15;       $r[38]=39;
584       $r[ 3]=4;     $r[15]=16;   $r[27]=28;       $r[39]=40;
585       $r[ 4]=5;     $r[16]=17;   $r[28]=29;       $r[40]=21;
586       $r[ 5]=18;    $r[17]=6;    $r[29]=30;       $r[41]=42;
587       $r[ 6]=41;    $r[18]=7;    $r[30]=31;       $r[42]=43;
588       $r[ 7]=22;    $r[19]=8;    $r[31]=32;       $r[43]=20;
589       $r[ 8]=45;    $r[20]=9;    $r[32]=33;       $r[44]=19;
590       $r[ 9]=46;    $r[21]=10;   $r[33]=44;       $r[45]=24;
591       $r[10]=35;    $r[22]=11;   $r[34]=48;       $r[46]=25;
592       $r[11]=36;    $r[23]=12;   $r[35]=34;       $r[47]=26;
593     }
594   else
595     {
596       /* check if we can find a game were non of the player was involved and return
597        * cards instead
598        */
599       $userstr = "'".implode("','",array($useridA,$useridB,$useridC,$useridD))."'";
600       $randomnumbers = DB_get_unused_randomnumbers($userstr);
601       $randomnumbers = explode(":",$randomnumbers);
602
603       if(sizeof($randomnumbers)==48)
604         return $randomnumbers;
605
606       /* need to create new numbers */
607       for($i=0;$i<48;$i++)
608         $r[$i]=$i+1;
609
610       /* shuffle using a better random generator than the standard one */
611       for ($i = 0; $i <48; $i++)
612         {
613           $j = @mt_rand(0, $i);
614           $tmp = $r[$i];
615           $r[$i] = $r[$j];
616           $r[$j] = $tmp;
617         }
618     };
619
620   return $r;
621 }
622
623 function display_cards($me,$myturn)
624 {
625   return;
626 }
627
628 function have_suit($cards,$c)
629 {
630   global $CARDS;
631   $suite = array();
632
633   if(in_array($c,$CARDS["trump"]))
634     $suite = $CARDS["trump"];
635   else if(in_array($c,$CARDS["clubs"]))
636     $suite = $CARDS["clubs"];
637   else if(in_array($c,$CARDS["spades"]))
638     $suite = $CARDS["spades"];
639   else if(in_array($c,$CARDS["hearts"]))
640     $suite = $CARDS["hearts"];
641   else if(in_array($c,$CARDS["diamonds"]))
642     $suite = $CARDS["diamonds"];
643
644   foreach($cards as $card)
645     {
646       if(in_array($card,$suite))
647         return 1;
648     }
649
650   return 0;
651 }
652
653 function same_type($card,$c)
654 {
655   global $CARDS;
656   $suite = "";
657
658   /* figure out what kind of card c is */
659   if(in_array($c,$CARDS["trump"]))
660     $suite = $CARDS["trump"];
661   else if(in_array($c,$CARDS["clubs"]))
662     $suite = $CARDS["clubs"];
663   else if(in_array($c,$CARDS["spades"]))
664     $suite = $CARDS["spades"];
665   else if(in_array($c,$CARDS["hearts"]))
666     $suite = $CARDS["hearts"];
667   else if(in_array($c,$CARDS["diamonds"]))
668     $suite = $CARDS["diamonds"];
669
670   /* card is the same suid return 1 */
671   if(in_array($card,$suite))
672     return 1;
673
674   return 0;
675 }
676
677 function set_gametype($gametype)
678 {
679   global $CARDS;
680   global $RULES;
681   global $GAME;
682
683   switch($gametype)
684     {
685     case "normal":
686     case "wedding":
687     case "poverty":
688     case "dpoverty":
689     case "trump":
690     case "silent":
691       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
692                                  '17','18','19','20','21','22','23','24','25','26');
693       $CARDS["diamonds"] = array();
694       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
695       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
696       $CARDS["hearts"]   = array('43','44','45','46','47','48');
697       $CARDS["foxes"]    = array('19','20');
698       if($RULES["dullen"]=='none')
699         {
700           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
701                                      '17','18','19','20','21','22','23','24','25','26');
702           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
703         }
704       /* do we need to reorder for Schweinchen? need to search for it because of special case for dullen above*/
705       if($RULES['schweinchen']=='both'&& $GAME['schweinchen-who'])
706         {
707           /* find the fox and put them at the top of the stack */
708           foreach(array('19','20') as $fox)
709             {
710               /* search for fox */
711               $trump = $CARDS['trump'];
712               $key = array_keys($trump, $fox);
713
714               /* reorder */
715               $foxa = array();
716               $foxa[]=$trump[$key[0]];
717               unset($trump[$key[0]]);
718               $trump = array_merge($foxa,$trump);
719               $CARDS['trump'] = $trump;
720             }
721         }
722       else if( ($RULES['schweinchen']=='second' || $RULES['schweinchen']=='secondaftercall')
723                && $GAME['schweinchen-who'])
724         {
725           /* find the fox and put them at the top of the stack */
726           $trump = $CARDS['trump'];
727           $key = array_keys($trump, '19');
728
729           /* reorder */
730           $foxa = array();
731           $foxa[]=$trump[$key[0]];
732           unset($trump[$key[0]]);
733           $trump = array_merge($foxa,$trump);
734           $CARDS['trump'] = $trump;
735         }
736       break;
737     case "queen":
738       $CARDS["trump"]    = array('3','4','5','6','7','8','9','10');
739       $CARDS["clubs"]    = array('27','28','29','30','31','32','11','12','33','34');
740       $CARDS["spades"]   = array('35','36','37','38','39','40','13','14','41','42');
741       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','15','16','47','48');
742       $CARDS["diamonds"] = array('19','20','21','22','23','24','17','18','25','26');
743       $CARDS["foxes"]    = array();
744       break;
745     case "jack":
746       $CARDS["trump"]    = array('11','12','13','14','15','16','17','18');
747       $CARDS["clubs"]    = array('27','28','29','30','31','32','3', '4','33','34');
748       $CARDS["spades"]   = array('35','36','37','38','39','40','5', '6','41','42');
749       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','7', '8','47','48');
750       $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','25','26');
751       $CARDS["foxes"]    = array();
752       break;
753     case "trumpless":
754       $CARDS["trump"]    = array();
755       $CARDS["clubs"]    = array('27','28','29','30','31','32','3', '4','11','12','33','34');
756       $CARDS["spades"]   = array('35','36','37','38','39','40','5', '6','13','14','41','42');
757       $CARDS["hearts"]   = array('43','44', '1', '2','45','46','7', '8','15','16','47','48');
758       $CARDS["diamonds"] = array('19','20','21','22','23','24','9','10','17','18','25','26');
759       $CARDS["foxes"]    = array();
760       break;
761     case "club":
762       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
763                                  '17','18','27','28','29','30','31','32','33','34');
764       $CARDS["clubs"]    = array();
765       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
766       $CARDS["hearts"]   = array('43','44','45','46','47','48');
767       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
768       $CARDS["foxes"]    = array();
769       if($RULES["dullen"]=='none')
770         {
771           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
772                                      '17','18','27','28','29','30','31','32','33','34');
773           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
774         }
775       break;
776     case "spade":
777       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
778                                  '17','18','35','36','37','38','39','40','41','42');
779       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
780       $CARDS["spades"]   = array();
781       $CARDS["hearts"]   = array('43','44','45','46','47','48');
782       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
783       $CARDS["foxes"]    = array();
784       if($RULES["dullen"]=='none')
785         {
786           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
787                                      '17','18','35','36','37','38','39','40','41','42');
788           $CARDS["hearts"]   = array('43','44','1','2','45','46','47','48');
789         }
790       break;
791     case "heart":
792       $CARDS["trump"]    = array('1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16',
793                                  '17','18','43','44','45','46','47','48');
794       $CARDS["clubs"]    = array('27','28','29','30','31','32','33','34');
795       $CARDS["spades"]   = array('35','36','37','38','39','40','41','42');
796       $CARDS["hearts"]   = array();
797       $CARDS["diamonds"] = array('19','20','21','22','23','24','25','26');
798       $CARDS["foxes"]    = array();
799       if($RULES["dullen"]=='none')
800         {
801           $CARDS["trump"]    = array('3','4','5','6','7','8','9','10','11','12','13','14','15','16',
802                             '17','18','43','44','1','2','45','46','47','48');
803         }
804       break;
805     }
806 }
807
808 function mysort($cards,$gametype)
809 {
810   global $PREF;
811   if(isset($PREF['sorting']))
812     if($PREF['sorting']=='high-low')
813       usort ( $cards, 'sort_comp_high_low' );
814     else
815       usort ( $cards, 'sort_comp_low_high' );
816   else
817     usort ( $cards, 'sort_comp_high_low' );
818   return $cards;
819 }
820
821 function sort_comp_high_low($a,$b)
822 {
823   global $CARDS;
824
825   $ALL = array();
826   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
827                      $CARDS['hearts'],$CARDS['spades']);
828
829   return pos_array($a,$ALL)-pos_array($b,$ALL);
830 }
831
832 function sort_comp_low_high($a,$b)
833 {
834   global $CARDS;
835
836   $ALL = array();
837   $ALL = array_merge($CARDS['trump'],$CARDS['diamonds'],$CARDS['clubs'],
838                      $CARDS['hearts'],$CARDS['spades']);
839
840   return -pos_array($a,$ALL)+pos_array($b,$ALL);
841 }
842
843 function can_call($what,$hash)
844 {
845   /* figure out if a person can make a call:
846    $what in 0,30,60,90,120 = points of the call
847    $hash                   = the hash of the person who wants to make the call
848
849    return values:
850    0   can't make that call
851    1   can make the call
852    2   can make the call, but this is the last chance to do so...
853    */
854
855   global $RULES;
856
857   /* get some information
858    */
859   $gameid   = DB_get_gameid_by_hash($hash);
860   $gametype = DB_get_gametype_by_gameid($gameid);
861   $oldcall  = DB_get_call_by_hash($hash); /* did the person already made a call? */
862   $pcall    = DB_get_partner_call_by_hash($hash); /* did the partner already made a call */
863
864
865   /* you're call must be better than the one you or your partner already made
866    */
867   if( ($pcall!=NULL && ($what >= $pcall))
868       || ($oldcall!=NULL && ($what >=$oldcall)) )
869     {
870       return 0;
871     }
872
873   /* for some rules we need to know how many cards people have
874    */
875   $NRcards  = count(DB_get_hand($hash));
876
877   $NRallcards = 0;
878   for ($i=1;$i<5;$i++)
879     {
880       $user         = DB_get_hash_from_game_and_pos($gameid,$i);
881       $NRallcards  += count(DB_get_hand($user));
882     };
883
884   /* in case of a wedding, everything will be delayed by an offset
885    */
886   $offset = 0;
887   if($gametype=="wedding")
888     {
889       $offset = DB_get_sickness_by_gameid($gameid);
890       if ($offset <0) /* not resolved */
891         return 0;
892     };
893
894   /* now check if the call is allowed depending on the rule set
895    */
896   switch ($RULES["call"])
897     {
898     case "1st-own-card":
899       /* calls can be made before/while you play your card...
900        * first card = 120, second card = 90, etc.
901        */
902       if( 4-($what/30) == 12 - ($NRcards + $offset))
903         return 2;
904       if( 4-($what/30) > 12 - ($NRcards + $offset))
905         return 1;
906       break;
907     case "5th-card":
908       /* you can make the first call anytime during the first trick
909        */
910       if( 27+4*($what/30) == $NRallcards + $offset*4)
911         return 2;
912       if( 27+4*($what/30) < $NRallcards + $offset*4)
913         return 1;
914       break;
915     case "9-cards":
916       /* you can call 120 with 12 cards, 90 with 9 or more cards, 60 with 6 or more, etc.
917        * you can't skip a call though
918        */
919
920       /* figure out last call
921        */
922       if($oldcall!=NULL && $pcall!=NULL)
923         $mincall = ($oldcall>$pcall) ? $pcall : $oldcall;
924       else if($oldcall!=NULL)
925         $mincall = $oldcall;
926       else if ($pcall!=NULL)
927         $mincall = $pcall;
928       else
929         $mincall = -1;
930
931
932       if( 12 == ($NRcards + $offset))
933         {
934           return 2;
935         }
936       else if( 12 < ($NRcards + $offset))
937         {
938           return 1;
939         }
940       else if ( 9 == ($NRcards + $offset))
941         {
942           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
943             return 2;
944         }
945       else if ( 9 < ($NRcards + $offset))
946         {
947           if( ($mincall>=0 && $mincall<=120 && $what<=90 ) )
948             return 1;
949         }
950       else if ( 6 == ($NRcards + $offset))
951         {
952           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
953             return 2;
954         }
955       else if ( 6 < ($NRcards + $offset))
956         {
957           if( ($mincall>=0 && $mincall<=90 && $what<=60 ) )
958             return 1;
959         }
960       else if ( 3 == ($NRcards + $offset))
961         {
962           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
963             return 2;
964         }
965       else if ( 3 < ($NRcards + $offset))
966         {
967           if( ($mincall>=0 && $mincall<=60 && $what<=30 ) )
968             return 1;
969         }
970       else if ( 0 == ($NRcards + $offset))
971         {
972           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
973             return 2;
974         }
975       else if ( 0 < ($NRcards + $offset))
976         {
977           if( ($mincall>=0 && $mincall<=30 && $what==0 ) )
978             return 1;
979         };
980       break;
981     }
982
983   return 0;
984 }
985
986 function display_table_begin ()
987 {
988   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
989   global $RULES,$GAME,$gametype;
990
991   $result = DB_query("SELECT  User.fullname as name,".
992                      "        Hand.position as position, ".
993                      "        User.id, ".
994                      "        Hand.party as party, ".
995                      "        Hand.sickness as sickness, ".
996                      "        Hand.point_call, ".
997                      "        User.last_login, ".
998                      "        Hand.hash,       ".
999                      "        User.timezone,    ".
1000                      "        User.email       ".
1001                      "FROM Hand ".
1002                      "LEFT JOIN User ON User.id=Hand.user_id ".
1003                      "WHERE Hand.game_id='".$gameid."' ".
1004                      "ORDER BY position ASC");
1005
1006   $row0 = DB_fetch_array($result);
1007   $row1 = DB_fetch_array($result);
1008   $row2 = DB_fetch_array($result);
1009   $row3 = DB_fetch_array($result);
1010
1011   echo "<div class=\"table\">\n";
1012   display_single_user($row1);
1013   echo "\n<div class=\"middle\">\n";
1014   display_single_user($row0,1); /* mark starting player in case re/contra is not set yet */
1015   echo "  <img class=\"table\" src=\"pics/table.png\" alt=\"table\" />\n";
1016   display_single_user($row2);
1017
1018   return;
1019 }
1020 function display_table_end ()
1021 {
1022   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1023   global $RULES,$GAME,$gametype;
1024
1025   $result = DB_query("SELECT  User.fullname as name,".
1026                      "        Hand.position as position, ".
1027                      "        User.id, ".
1028                      "        Hand.party as party, ".
1029                      "        Hand.sickness as sickness, ".
1030                      "        Hand.point_call, ".
1031                      "        User.last_login, ".
1032                      "        Hand.hash,       ".
1033                      "        User.timezone,    ".
1034                      "        User.email       ".
1035                      "FROM Hand ".
1036                      "LEFT JOIN User ON User.id=Hand.user_id ".
1037                      "WHERE Hand.game_id='".$gameid."' ".
1038                      "ORDER BY position ASC");
1039
1040   $row0 = DB_fetch_array($result);
1041   $row1 = DB_fetch_array($result);
1042   $row2 = DB_fetch_array($result);
1043   $row3 = DB_fetch_array($result);
1044
1045   echo "</div>\n";
1046   display_single_user($row3);
1047   echo "</div>\n";
1048
1049   return;
1050 }
1051
1052 function display_single_user($r,$start=0)
1053 {
1054   /* start=1, mark starting player, default=0, so the player on the left is not marked */
1055
1056   global $gameid, $GT, $debug,$INDEX,$defaulttimezone,$session;
1057   global $RULES,$GAME,$gametype;
1058
1059       $name  = $r[0];
1060       $pos   = $r[1];
1061       $user  = $r[2];
1062       $party = $r[3];
1063       $sickness  = $r[4];
1064       $call      = $r[5];
1065       $hash      = $r[7];
1066       $timezone  = $r[8];
1067       $email     = $r[9];
1068       $wins      = DB_get_number_of_tricks($gameid,$pos);
1069       date_default_timezone_set($defaulttimezone);
1070       $lastlogin = strtotime($r[6]);
1071       date_default_timezone_set($timezone);
1072       $timenow   = strtotime(date("Y-m-d H:i:s"));
1073       $gravatar = "$name<br />\n       <img class=\"gravatar\" title=\"$name\" src=\"http://www.gravatar.com/avatar/".
1074         md5(strtolower(trim($email)))."?d=identicon\" alt=\"$name's gravatar\" />";
1075
1076       echo "  <div class=\"table".($pos-1)."\">\n";
1077
1078       /* mark starting player */
1079       if($start && ! ($party=="re" || $party=="contra"))
1080         echo '   <span class="start">'._('Starting Player')."</span> <br />\n";
1081
1082       if($debug)
1083         echo "   <a href=\"".$INDEX."?action=game&amp;me=".$hash."\">";
1084       if($vacation = check_vacation($user))
1085         {
1086           $start   = $vacation[0];
1087           $stop    = substr($vacation[1],0,10);
1088           $comment = $vacation[2];
1089
1090           $title = _("begin:")." $start  "._("end:")." $stop $comment";
1091               echo "   <span class=\"vacation\" title=\"$title\">$gravatar "._("(on vacation until $stop)")."</span> \n";
1092         }
1093       else
1094         echo "   $gravatar \n";
1095       if($debug)
1096         echo"   </a>\n";
1097
1098       /* add hints for poverty, wedding, solo, etc */
1099       if( $gametype != "solo")
1100         if( $RULES["schweinchen"]=="both" && $GAME["schweinchen-who"]==$hash )
1101           echo " Schweinchen. <br />";
1102
1103       if($GT=="poverty" && $party=="re")
1104         if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1105           {
1106             $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1107             $cards    = DB_get_all_hand($userhash);
1108             $trumpNR  = count_trump($cards,'all');
1109             if($trumpNR)
1110               echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1111                 "alt=\"poverty - trump back\" title=\"poverty - trump back\" />\n";
1112             else
1113               echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1114                 "alt=\"poverty - no trump back\" title=\"poverty - no trump back\" />\n";
1115           }
1116         else
1117           echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1118             "alt=\"poverty partner\" title=\"poverty partner\" />\n";
1119
1120       if($GT=="dpoverty")
1121         if($party=="re")
1122           if($sickness=="poverty" || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1123             {
1124               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1125               $cards    = DB_get_all_hand($userhash);
1126               $trumpNR  = count_trump($cards,'all');
1127               if($trumpNR)
1128                 echo "   <img src=\"pics/button/poverty_trump_button.png\" class=\"button\" ".
1129                   "alt=\"poverty < trump back\" title=\"poverty - trump back\" />\n";
1130               else
1131                 echo "   <img src=\"pics/button/poverty_notrump_button.png\" class=\"button\" ".
1132                   "alt=\"poverty <\" title=\"poverty - no trump back\" />\n";
1133             }
1134           else
1135             echo "   <img src=\"pics/button/poverty_partner_button.png\" class=\"button\" ".
1136               "alt=\"poverty >\" title=\"poverty partner\" />\n";
1137         else
1138           if($sickness=="poverty"  || ($RULES['lowtrump']=='poverty' && $sickness=='lowtrump'))
1139             {
1140               $userhash = DB_get_hash_from_gameid_and_userid($gameid,$user);
1141               $cards    = DB_get_all_hand($userhash);
1142               $trumpNR  = count_trump($cards,'all');
1143               if($trumpNR)
1144                 echo "   <img src=\"pics/button/poverty2_trump_button.png\" class=\"button\" ".
1145                   "alt=\"poverty2 < trump back\" title=\"poverty2 - trump back\"/>\n";
1146               else
1147                 echo "   <img src=\"pics/button/poverty2_notrump_button.png\" class=\"button\" ".
1148                   "alt=\"poverty2 <\" title=\"poverty2 - no trump back\" />\n";
1149             }
1150           else
1151             echo "   <img src=\"pics/button/poverty2_partner_button.png\" class=\"button\" ".
1152               "alt=\"poverty2 >\" title=\"poverty2 partner\" />\n";
1153
1154       if($GT=="wedding" && $party=="re")
1155         if($sickness=="wedding")
1156           echo "   <img src=\"pics/button/wedding_button.png\" class=\"button\" alt=\"wedding\" title=\"wedding\" />\n";
1157         else
1158           echo "   <img src=\"pics/button/wedding_partner_button.png\" class=\"button\" ".
1159             "alt=\"wedding partner\" title=\"wedding partner\" />\n";
1160
1161       if( (strpos($GT,"solo")!==false) && $party=="re")
1162         {
1163           if(strpos($GT,"queen")!==false)
1164             echo "   <img src=\"pics/button/queensolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Queen solo\" />\n";
1165           else if(strpos($GT,"jack")!==false)
1166             echo "   <img src=\"pics/button/jacksolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Jack solo\" />\n";
1167           else if(strpos($GT,"club")!==false)
1168             echo "   <img src=\"pics/button/clubsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Club solo\" />\n";
1169           else if(strpos($GT,"spade")!==false)
1170             echo "   <img src=\"pics/button/spadesolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Spade solo\" />\n";
1171           else if(strpos($GT,"heart")!==false)
1172             echo "   <img src=\"pics/button/heartsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Heart solo\" />\n";
1173           else if(strpos($GT,"trumpless")!==false)
1174             echo "   <img src=\"pics/button/notrumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trumpless solo\" />\n";
1175           else if(strpos($GT,"trump")!==false)
1176             echo "   <img src=\"pics/button/trumpsolo_button.png\" class=\"button\" alt=\"$GT\" title=\"Trump solo\" />\n";
1177         }
1178
1179       /* add point calls */
1180       if($call!=NULL)
1181         {
1182           if($party=="re")
1183             echo "   <img src=\"pics/button/re_button.png\" class=\"button\" alt=\"re\" title=\"Re\" />\n";
1184           else
1185             echo "   <img src=\"pics/button/contra_button.png\" class=\"button\" alt=\"contra\" title=\"Contra\" />\n";
1186           switch($call)
1187             {
1188             case "0":
1189               echo "   <img src=\"pics/button/0_button.png\" class=\"button\" alt=\"0\" title=\"Call 0\" />\n";
1190               break;
1191             case "30":
1192               echo "   <img src=\"pics/button/30_button.png\" class=\"button\" alt=\"30\" title=\"Call 30\" />\n";
1193               break;
1194             case "60":
1195               echo "   <img src=\"pics/button/60_button.png\" class=\"button\" alt=\"60\" title=\"Call 60\" />\n";
1196               break;
1197             case "90":
1198               echo "   <img src=\"pics/button/90_button.png\" class=\"button\" alt=\"90\" title=\"Call 90\" />\n";
1199               break;
1200             }
1201         }
1202
1203       echo "   <img src=\"pics/button/time-info.png\" class=\"button\" alt=\"time info\" ".
1204         "title=\"local time: ".date("Y-m-d H:i:s",$timenow).  " ".
1205         "last login: ".date("Y-m-d H:i:s",$lastlogin)."\" />";
1206
1207       echo "   <br /><span class=\"numberoftricks\">";
1208       /* show how many tricks the person made */
1209       switch($wins)
1210         {
1211         case 0:
1212           echo _('#tricks 0'); break;
1213         case 1:
1214           echo _('#tricks 1'); break;
1215         case 2:
1216         case 3:
1217         case 4:
1218           echo _('#tricks few'); break;
1219         default:
1220           echo _('#tricks many'); break;
1221         }
1222       echo "</span>\n";
1223       echo "  </div>\n";
1224 }
1225
1226
1227 function display_user_menu($id, $skiphash=NULL)
1228 {
1229   global $WIKI,$INDEX;
1230
1231   if($skiphash)
1232     $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1233                        " LEFT JOIN Game On Hand.game_id=Game.id".
1234                        " WHERE Hand.user_id='$id'".
1235                        " AND Hand.hash!='$skiphash'".
1236                        " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1237                        " AND ( Game.status='pre' OR Game.status='play' )".
1238                        " ORDER BY Game.session" );
1239   else
1240     $result = DB_query("SELECT Hand.hash,Hand.game_id,Game.player from Hand".
1241                        " LEFT JOIN Game On Hand.game_id=Game.id".
1242                        " WHERE Hand.user_id='$id'".
1243                        " AND ( Game.player='$id' OR ISNULL(Game.player) )".
1244                        " AND ( Game.status='pre' OR Game.status='play' )".
1245                        " ORDER BY Game.session" );
1246
1247   $i=0;
1248   while( $r = DB_fetch_array($result))
1249     {
1250       if($i==0)
1251         {
1252           echo "\n<div class=\"usermenu\">\n  ";
1253           echo _('It\'s your turn in these games').":\n";
1254         }
1255       else
1256         {
1257           echo ", ";
1258         }
1259
1260       $i++;
1261       echo "  <a href=\"".$INDEX."?action=game&amp;me=".$r[0].
1262         "\"> ".DB_format_gameid($r[1])." </a>\n";
1263       if($i>4)
1264         {
1265           echo ",  ...\n";
1266           break;
1267         }
1268     }
1269
1270   if($i)
1271     echo  "</div>\n\n";
1272   return;
1273 }
1274
1275 function generate_score_table($session)
1276 {
1277   /* returns an array with N entries
1278    * $score[$i]["gameid"]   = gameid
1279    * $score[$i]["players"] = array (id=>total points)
1280    * $score[$i]["points"]   = points for this game
1281    * $score[$i]["solo"]     = 1 or 0
1282    */
1283   $score = array();
1284   $i=0;
1285
1286   /* get all ids, scores and gametypes */
1287   $gameids = DB_get_gameids_of_finished_games_by_session($session);
1288
1289   if($gameids == NULL)
1290     return $score;
1291
1292   $player = array();
1293   $player_party = array();
1294
1295   /* get player id from the first game */
1296   $result = DB_query("SELECT user_id from Hand".
1297                      " WHERE Hand.game_id=".$gameids[0][0]);
1298   while( $r = DB_fetch_array($result))
1299     $player[$r[0]] = 0;
1300
1301   /* get party of players for each game in the session */
1302   foreach($player as $id=>$points)
1303     $player_party[$id]=DB_get_party_by_session_and_userid($session,$id);
1304
1305   /* get points and generate table */
1306   foreach($gameids as $gameid)
1307     {
1308       $re_score = $gameid[1];
1309       $gametype = $gameid[2];
1310       foreach($player as $id=>$points)
1311         {
1312           $party = $player_party[$id][$i][0];
1313           if($party == "re")
1314             if($gametype=="solo")
1315               $player[$id] += 3*$re_score;
1316             else
1317               $player[$id] += $re_score;
1318           else if ($party == "contra")
1319             $player[$id] -= $re_score;
1320         }
1321       $score[$i]['gameid']  = $gameid[0] ;
1322       $score[$i]['players'] = $player;
1323       $score[$i]['points']  = abs($re_score);
1324       $score[$i]['solo']    = ($gametype=="solo");
1325
1326       $i++;
1327     }
1328
1329   return $score;
1330 }
1331
1332 function generate_global_score_table()
1333 {
1334   $return = array();
1335
1336   /* get all ids, scores and gametypes */
1337   $gameids = DB_get_gameids_of_finished_games_by_session(0);
1338
1339   if($gameids == NULL)
1340     return '';
1341
1342   $player = array();
1343   /* get player id, names... from the User table */
1344   $result = DB_query('SELECT User.id, User.fullname FROM User');
1345
1346   /* save information in an array */
1347   while( $r = DB_fetch_array($result))
1348     $player[$r[0]] = array('name'=> $r[1], 'points' => 0 , 'nr' => 0, 'active' => 0,
1349                            'response' => 0 , 'solo' => 0, 'soloavg' => 0);
1350
1351   /* get points and generate table */
1352   foreach($gameids as $gameid)
1353     {
1354       $re_score = $gameid[1];
1355       $gametype = $gameid[2];
1356
1357       /* get players involved in this game */
1358       $result = DB_query('SELECT user_id FROM Hand WHERE game_id='.DB_quote_smart($gameid[0]));
1359       while($r = DB_fetch_array($result))
1360         {
1361           $id = $r[0];
1362           $party = DB_get_party_by_gameid_and_userid($gameid[0],$id);
1363           if($party == 're')
1364             if($gametype=='solo')
1365               $player[$id]['points'] += 3*$re_score;
1366             else
1367               $player[$id]['points'] += $re_score;
1368           else if ($party == 'contra')
1369             $player[$id]['points'] -= $re_score;
1370           if($party)
1371             $player[$id]['nr']+=1;
1372         }
1373     }
1374
1375   /* add number of active games */
1376   $result = DB_query_array_all("SELECT user_id, COUNT(*) as c  " .
1377                                " FROM Hand".
1378                                " LEFT JOIN Game ON Game.id=game_id".
1379                                " WHERE Game.status IN ('pre','play')".
1380                                " GROUP BY user_id");
1381
1382   foreach($result as $res)
1383     {
1384       $player[$res[0]]['active'] = $res[1];
1385     }
1386
1387   /* response time of users*/
1388   $result = DB_query_array_all("SELECT user_id,".
1389                               "IFNULL(AVG(if(P1.sequence in (2,3,4),".
1390                               "-timestampdiff(MINUTE,mod_date,(select mod_date from Play P2 where P1.trick_id=P2.trick_id  and P2.sequence=P1.sequence-1)),NULL )),1e9) as a ".
1391                               "FROM Play P1 ".
1392                               "LEFT JOIN Hand_Card ON P1.hand_card_id=Hand_Card.id ".
1393                               "LEFT JOIN Hand ON Hand.id=Hand_Card.hand_id ".
1394                               "GROUP BY user_id ");
1395
1396   foreach($result as $res)
1397     {
1398       $player[$res[0]]['response'] = $res[1];
1399     }
1400
1401   /* most solos */
1402   $result = DB_query_array_all("SELECT user_id as uid,".
1403                                "       COUNT(*), ".
1404                                "       COUNT(*)/(SELECT COUNT(*) FROM Hand LEFT JOIN User ON User.id=Hand.user_id WHERE User.id=uid) as c ".
1405                                " FROM Game ".
1406                                " LEFT JOIN Hand ON Hand.position=startplayer AND Game.id=Hand.game_id ".
1407                                " WHERE type='solo' AND Game.status='gameover' ".
1408                                " GROUP BY user_id ");
1409
1410   foreach($result as $res)
1411     {
1412       $player[$res[0]]['solo'] = $res[1];
1413       $player[$res[0]]['soloavg'] = $res[2];
1414     }
1415
1416
1417   /* sort everything nicely */
1418
1419   function cmp($a,$b)
1420   {
1421     if($a['nr']==0) return 1;
1422     if($b['nr']==0) return 1;
1423
1424     $a=$a['points']/$a['nr'];
1425     $b=$b['points']/$b['nr'];
1426
1427     if ($a == $b)
1428       return 0;
1429     return ($a > $b) ? -1 : 1;
1430   }
1431   usort($player,'cmp');
1432
1433
1434   foreach($player as $pl)
1435     {
1436       /* limit to players with at least 10 games */
1437       if($pl['nr']>10)
1438         $return[] = array( $pl['name'], round($pl['points']/$pl['nr'],3), $pl['points'],$pl['nr'],$pl['active'],
1439                            $pl['response'],$pl['solo'],$pl['soloavg']);
1440     }
1441
1442   return $return;
1443 }
1444
1445 function format_score_table_ascii($score)
1446 {
1447   $output="";
1448   if(sizeof($score)==0)
1449     return "";
1450
1451   /* truncate table if we have too many games */
1452   $max = sizeof($score);
1453   if($max>6) $output.=" "._("(table truncated to last 6 games)")."\n";
1454
1455   /* output header */
1456   foreach($score[0]['players'] as $id=>$points)
1457     {
1458       $name = DB_get_name('userid',$id); /*TODO*/
1459       $output.= "  ".substr($name,0,2)."  |";
1460     }
1461   $output.="  P   |\n";
1462   $output.= "------+------+------+------+------+\n";
1463
1464   /* output score for each game */
1465   $i=0;
1466   foreach($score as $game)
1467     {
1468       $i++;
1469       if($i-1<$max-6) continue;
1470
1471       foreach($game['players'] as $id=>$points)
1472         $output.=str_pad($points,6," ",STR_PAD_LEFT)."|";
1473       $output.=str_pad($game['points'],4," ",STR_PAD_LEFT);
1474
1475       /* check for solo */
1476       if($game['solo'])
1477         $output.= " S|";
1478       else
1479         $output.= "  |";
1480
1481       $output.="\n";
1482     }
1483   return $output;
1484 }
1485
1486 function format_score_table_html($score,$userid)
1487 {
1488   global $INDEX;
1489
1490   if(sizeof($score)==0)
1491     return "";
1492
1493   $output = "<div class=\"scoretable\">\n<table class=\"score\">\n";
1494
1495   /* output header */
1496   $header = "";
1497   $header.= " <thead>\n  <tr>\n";
1498   $header.= "   <th> No </th>";
1499   foreach($score[0]['players'] as $id=>$points)
1500     {
1501       $name = DB_get_name('userid',$id); /*TODO*/
1502       $header.= "<th> ".substr($name,0,2)." </th>";
1503     }
1504   $header.="<th>P</th>\n  </tr>\n </thead>\n";
1505
1506   /* use the same as footer */
1507   $footer = "";
1508   $footer.= " <tfoot>\n  <tr>\n";
1509   $footer.= "   <td> No </td>";
1510   foreach($score[0]['players'] as $id=>$points)
1511     {
1512       $name = DB_get_name('userid',$id); /*TODO*/
1513       $footer.= "<td> ".substr($name,0,2)." </td>";
1514     }
1515   $footer.="<td>P</td>\n  </tr>\n </tfoot>\n";
1516
1517   /* body */
1518   $body = "";
1519   $body.= " <tbody>\n";
1520   $i=0;
1521   foreach($score as $game)
1522     {
1523       $i++;
1524       $body.="  <tr>";
1525       $userhash = DB_get_hash_from_gameid_and_userid($game['gameid'],$userid);
1526       /* create link to old games only if you are logged in and its your game*/
1527       if(isset($_SESSION['id']) && $_SESSION['id']==$userid)
1528         $body.="  <td> <a href=\"".$INDEX."?action=game&amp;me=".$userhash."\">$i</a></td>";
1529       else
1530         $body.="  <td>$i</td>";
1531
1532       foreach($game['players'] as $id=>$points)
1533         $body.="<td>".$points."</td>";
1534       $body.="<td>".$game['points'];
1535
1536       /* check for solo */
1537       if($game['solo'])
1538         $body.= " S";
1539       $body.="</td></tr>\n";
1540     }
1541
1542   $output.=$header;
1543   if($i>12)
1544     $output.=$footer;
1545   $output.=$body;
1546
1547   $output.=" </tbody>\n</table>\n</div>\n";
1548
1549   return $output;
1550 }
1551
1552 function createCache($content, $cacheFile)
1553 {
1554   $fp = fopen($cacheFile,"w");
1555   if($fp)
1556     {
1557       fwrite($fp,$content);
1558       fclose($fp);
1559     }
1560   else
1561     echo "WARNING: couldn't create cache file";
1562
1563   return;
1564 }
1565
1566 function getCache($cacheFile, $expireTime)
1567 {
1568   if( file_exists($cacheFile) &&
1569       filemtime($cacheFile )>( time() - $expireTime ) )
1570     {
1571       return file_get_contents($cacheFile);
1572     }
1573
1574   return false;
1575 }
1576
1577 function check_vacation($userid)
1578 {
1579   /* get start date */
1580   $result = DB_query_array("SELECT value FROM User_Prefs".
1581                      " WHERE user_id='$userid' AND pref_key='vacation start'" );
1582   if($result)
1583     $start = $result[0];
1584   else
1585     return NULL;
1586
1587   /* get end date */
1588   $result = DB_query_array("SELECT value FROM User_Prefs".
1589                      " WHERE user_id='$userid' AND pref_key='vacation stop'" );
1590   if($result)
1591     $stop = $result[0];
1592   else
1593     return NULL;
1594
1595   /* get comment */
1596   $result = DB_query_array("SELECT value FROM User_Prefs".
1597                      " WHERE user_id='$userid' AND pref_key='vacation comment'" );
1598   if($result)
1599     $comment = $result[0];
1600   else
1601     $comment = '';
1602
1603   /* check if user is on vacation. TODO: use user's timezone */
1604   if( (time() - strtotime($start) >0) &&
1605       (strtotime($stop) - time()  >0))
1606     return array ($start,$stop,$comment);
1607   else
1608     return NULL;
1609 }
1610
1611 function cancel_game($why,$gameid)
1612 {
1613   $gameid = DB_quote_smart($gameid);
1614
1615   /* update the game table */
1616   switch($why)
1617     {
1618     case 'timedout':
1619       DB_query("UPDATE Game SET status='cancel-timedout' WHERE id=$gameid");
1620       break;
1621     case 'nines':
1622       DB_query("UPDATE Game SET status='cancel-nines' WHERE id=$gameid");
1623       break;
1624     case 'trump':
1625       DB_query("UPDATE Game SET status='cancel-trump' WHERE id=$gameid");
1626       break;
1627     case 'noplay':
1628       DB_query("UPDATE Game SET status='cancel-noplay' WHERE id=$gameid");
1629       break;
1630     case 'lowtrump':
1631       DB_query("UPDATE Game SET status='cancel-lowtrump' WHERE id=$gameid");
1632       break;
1633     }
1634   /* set each player to gameover */
1635   $result = DB_query("SELECT id FROM Hand WHERE game_id=".DB_quote_smart($gameid));
1636   while($r = DB_fetch_array($result))
1637     {
1638       $id = $r[0];
1639       DB_query("UPDATE Hand SET status='gameover' WHERE id=".DB_quote_smart($id));
1640     }
1641
1642   return;
1643 }
1644
1645 function get_user_token($userid)
1646 {
1647
1648   $token = NULL;
1649
1650   $date = DB_get_user_creation_date($userid);
1651   $name = DB_get_name('userid',$userid);
1652
1653   if($date && $name)
1654     $token = md5("token".$name.$date);
1655
1656   return $token;
1657 }
1658
1659 function verify_password($email, $password)
1660 {
1661   /* verify password, if old password has length 32 assume it's an old md5, else use new password scheme */
1662   /* return 0 if verified, else return error code
1663    *        1 can't find email
1664    *        2 can't calculate correct hash
1665    *        3 misc error
1666    */
1667
1668   /* check user email by getting his id */
1669   $userid = DB_get_userid('email',$email);
1670   if(!$userid)
1671     return 1;
1672
1673   /* test for temporary passwords, only valid for one date (tested in the DB) */
1674   $tmppasswd = md5($password);
1675   if(DB_check_recovery_passwords($tmppasswd,$email))
1676     return 0;
1677
1678   /* get saved password */
1679   $existingpassword =  DB_get_passwd_by_userid($userid);
1680
1681   if(strlen($existingpassword)==32) /* old password type */
1682     {
1683       if ($existingpassword == md5($password))
1684         {
1685           /* update password to new crypt version */
1686           // create a password hash using the crypt function, need php 5.3 for this
1687           // create and random salt
1688           $salt = substr(str_replace('+', '.', base64_encode(sha1(microtime(true), true))), 0, 22);
1689           // hash incoming password using 12 rounds of blowfish
1690           $hash = crypt($password, '$2y$12$' . $salt);
1691           if(strlen($hash)>13)
1692             DB_query("UPDATE User SET password='$hash' where id='$userid'");
1693           else
1694             return 2;
1695
1696           return 0;
1697         }
1698     }
1699   else
1700     {
1701       if ($existingpassword == crypt($password, $existingpassword))
1702         return 0;
1703     };
1704
1705   return 3;
1706 }
1707
1708 /* language functions */
1709 function detectlanguage()
1710 {
1711         /* read out browser's prefered language, taken from php-manual*/
1712         $langcode = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
1713         $langcode = explode(",", $langcode['0']);
1714         return $langcode['0'];
1715 }
1716
1717 function set_language($l,$type='lang')
1718 {
1719    if($type=='uid')
1720      {
1721        $userPREF = DB_get_PREF($l);
1722        $l = $userPREF['language'];
1723      };
1724
1725     switch($l)
1726       {
1727       case 'de':
1728         putenv("LC_ALL=de_DE");
1729         setlocale(LC_ALL, "de_DE");
1730         break;
1731       default:
1732         putenv("LC_ALL=en_US");
1733         setlocale(LC_ALL, "en_US");
1734         break;
1735       }
1736
1737     // Specify location of translation tables
1738     bindtextdomain("edoko", "./locale");
1739     bind_textdomain_codeset("edoko", 'UTF-8');
1740     // Choose domain
1741     textdomain("edoko");
1742
1743     return;
1744 }
1745
1746 ?>