/ miner.php
miner.php
   1  <?php
   2  session_start();
   3  #
   4  global $doctype, $title, $miner, $port, $readonly, $notify;
   5  global $rigport, $rigs, $rignames, $rigbuttons;
   6  global $mcast, $mcastexpect, $mcastaddr, $mcastport, $mcastcode;
   7  global $mcastlistport, $mcasttimeout, $mcastretries, $allowgen;
   8  global $rigipsecurity, $rigtotals, $forcerigtotals;
   9  global $socksndtimeoutsec, $sockrcvtimeoutsec;
  10  global $checklastshare, $poolinputs, $hidefields;
  11  global $ignorerefresh, $changerefresh, $autorefresh;
  12  global $allowcustompages, $customsummarypages, $user_pages;
  13  global $miner_font_family, $miner_font_size;
  14  global $bad_font_family, $bad_font_size, $add_css_names;
  15  global $colouroverride, $placebuttons, $userlist;
  16  #
  17  $doctype = "<!DOCTYPE html>\n";
  18  #
  19  # See API-README for more details of these variables and how
  20  # to configure miner.php
  21  #
  22  # Web page title
  23  $title = 'Mine';
  24  #
  25  # Set $readonly to true to force miner.php to be readonly
  26  # Set $readonly to false then it will check cgminer 'privileged'
  27  $readonly = false;
  28  #
  29  # Set $userlist to null to allow anyone access or read API-README
  30  $userlist = null;
  31  #
  32  # Set $notify to false to NOT attempt to display the notify command
  33  # Set $notify to true to attempt to display the notify command
  34  $notify = true;
  35  #
  36  # Set $checklastshare to true to do the following checks:
  37  # If a device's last share is 12x expected ago then display as an error
  38  # If a device's last share is 8x expected ago then display as a warning
  39  # If either of the above is true, also display the whole line highlighted
  40  # This assumes shares are 1 difficulty shares
  41  $checklastshare = true;
  42  #
  43  # Set $poolinputs to true to show the input fields for adding a pool
  44  # and changing the pool priorities
  45  # N.B. also if $readonly is true, it will not display the fields
  46  $poolinputs = false;
  47  #
  48  # Default port to use if any $rigs entries don't specify the port number
  49  $rigport = 4028;
  50  #
  51  # Set $rigs to an array of your cgminer rigs that are running
  52  #  format: 'IP' or 'Host' or 'IP:Port' or 'Host:Port' or 'Host:Port:Name'
  53  $rigs = array('127.0.0.1:4028');
  54  #
  55  # Set $rignames to false, or one of 'ip' or 'ipx'
  56  #  this says what to use if $rigs doesn't have a 'name'
  57  $rignames = false;
  58  #
  59  # Set $rigbuttons to false to display a link rather than a button
  60  $rigbuttons = true;
  61  #
  62  # Set $mcast to true to look for your rigs and ignore $rigs
  63  $mcast = false;
  64  #
  65  # Set $mcastexpect to at least how many rigs you expect it to find
  66  $mcastexpect = 0;
  67  #
  68  # API Multicast address all cgminers are listening on
  69  $mcastaddr = '224.0.0.75';
  70  #
  71  # API Multicast UDP port all cgminers are listening on
  72  $mcastport = 4028;
  73  #
  74  # The code all cgminers expect in the Multicast message sent
  75  $mcastcode = 'FTW';
  76  #
  77  # UDP port cgminers are to reply on (by request)
  78  $mcastlistport = 4027;
  79  #
  80  # Set $mcasttimeout to the number of seconds (floating point)
  81  # to wait for replies to the Multicast message
  82  $mcasttimeout = 1.5;
  83  #
  84  # Set $mcastretries to the number of times to retry the multicast
  85  $mcastretries = 0;
  86  #
  87  # Set $allowgen to true to allow customsummarypages to use 'gen' 
  88  # false means ignore any 'gen' options
  89  $allowgen = false;
  90  #
  91  # Set $rigipsecurity to false to show the IP/Port of the rig
  92  # in the socket error messages and also show the full socket message
  93  $rigipsecurity = true;
  94  #
  95  # Set $rigtotals to true to display totals on the single rig page
  96  # 'false' means no totals (and ignores $forcerigtotals)
  97  # You can force it to always show rig totals when there is only
  98  # one line by setting $forcerigtotals = true;
  99  $rigtotals = true;
 100  $forcerigtotals = false;
 101  #
 102  # These should be OK for most cases
 103  $socksndtimeoutsec = 10;
 104  $sockrcvtimeoutsec = 40;
 105  #
 106  # List of fields NOT to be displayed
 107  # This example would hide the slightly more sensitive pool information
 108  #$hidefields = array('POOL.URL' => 1, 'POOL.User' => 1);
 109  $hidefields = array();
 110  #
 111  # Auto-refresh of the page (in seconds) - integers only
 112  # $ignorerefresh = true/false always ignore refresh parameters
 113  # $changerefresh = true/false show buttons to change the value
 114  # $autorefresh = default value, 0 means dont auto-refresh
 115  $ignorerefresh = false;
 116  $changerefresh = true;
 117  $autorefresh = 0;
 118  #
 119  # Should we allow custom pages?
 120  # (or just completely ignore them and don't display the buttons)
 121  $allowcustompages = true;
 122  #
 123  # OK this is a bit more complex item: Custom Summary Pages
 124  # As mentioned above, see API-README
 125  # see the example below (if there is no matching data, no total will show)
 126  $mobilepage = array(
 127   'DATE' => null,
 128   'RIGS' => null,
 129   'SUMMARY' => array('Elapsed', 'MHS av', 'MHS 5m', 'Found Blocks=Blks',
 130  			'Difficulty Accepted=DiffA',
 131  			'Difficulty Rejected=DiffR',
 132  			'Hardware Errors=HW',
 133  			'Work Utility=WU'),
 134   'DEVS+NOTIFY' => array('DEVS.Name=Name', 'DEVS.ID=ID', 'DEVS.Status=Status',
 135  			'DEVS.Temperature=Temp', 'DEVS.MHS av=MHS av',
 136  			'DEVS.MHS 5m=MHS 5m', 'DEVS.Difficulty Accepted=DiffA',
 137  			'DEVS.Difficulty Rejected=DiffR',
 138  			'DEVS.Work Utility=WU',
 139  			'NOTIFY.Last Not Well=Not Well'),
 140   'POOL' => array('POOL', 'Status', 'Difficulty Accepted=DiffA',
 141  			'Difficulty Rejected=DiffR', 'Last Share Time=LST'));
 142  $mobilesum = array(
 143   'SUMMARY' => array('MHS av', 'MHS 5m', 'Found Blocks', 'Difficulty Accepted',
 144  			'Difficulty Rejected', 'Hardware Errors',
 145  			'Work Utility'),
 146   'DEVS+NOTIFY' => array('DEVS.MHS av', 'DEVS.Difficulty Accepted',
 147  			'DEVS.Difficulty Rejected'),
 148   'POOL' => array('Difficulty Accepted', 'Difficulty Rejected'));
 149  #
 150  $statspage = array(
 151   'DATE' => null,
 152   'RIGS' => null,
 153   'SUMMARY' => array('Elapsed', 'MHS av', 'MHS 5m', 'Found Blocks=Blks',
 154  			'Difficulty Accepted=DiffA',
 155  			'Difficulty Rejected=DiffR',
 156  			'Work Utility=WU', 'Hardware Errors=HW Errs',
 157  			'Network Blocks=Net Blks'),
 158   'COIN' => array('*'),
 159   'STATS' => array('*'));
 160  #
 161  $statssum = array(
 162   'SUMMARY' => array('MHS av', 'MHS 5m', 'Found Blocks',
 163  			'Difficulty Accepted', 'Difficulty Rejected',
 164  			'Work Utility', 'Hardware Errors'));
 165  #
 166  $poolspage = array(
 167   'DATE' => null,
 168   'RIGS' => null,
 169   'SUMMARY' => array('Elapsed', 'MHS av', 'MHS 5m', 'Found Blocks=Blks',
 170  			'Difficulty Accepted=DiffA',
 171  			'Difficulty Rejected=DiffR',
 172  			'Work Utility', 'Hardware Errors=HW',
 173  			'Network Blocks=Net Blks', 'Best Share'),
 174   'POOL+STATS' => array('STATS.ID=ID', 'POOL.URL=URL',
 175  			'POOL.Difficulty Accepted=DiffA',
 176  			'POOL.Difficulty Rejected=DiffR',
 177  			'POOL.Has Stratum=Stratum',
 178  			'POOL.Stratum Active=StrAct',
 179  			'POOL.Has GBT=GBT', 'STATS.Times Sent=TSent',
 180  			'STATS.Bytes Sent=BSent', 'STATS.Net Bytes Sent=NSent',
 181  			'STATS.Times Recv=TRecv', 'STATS.Bytes Recv=BRecv',
 182  			'STATS.Net Bytes Recv=NRecv', 'GEN.AvShr=AvShr'));
 183  #
 184  $poolssum = array(
 185   'SUMMARY' => array('MHS av', 'MHS 5m', 'Found Blocks',
 186  			'Difficulty Accepted', 'Difficulty Rejected',
 187  			'Work Utility', 'Hardware Errors'),
 188   'POOL+STATS' => array('POOL.Difficulty Accepted', 'POOL.Difficulty Rejected',
 189  			'STATS.Times Sent', 'STATS.Bytes Sent',
 190  			'STATS.Net Bytes Sent', 'STATS.Times Recv',
 191  			'STATS.Bytes Recv', 'STATS.Net Bytes Recv'));
 192  #
 193  $poolsext = array(
 194   'POOL+STATS' => array(
 195  	'where' => null,
 196  	'group' => array('POOL.URL', 'POOL.Has Stratum',
 197  				'POOL.Stratum Active', 'POOL.Has GBT'),
 198  	'calc' => array('POOL.Difficulty Accepted' => 'sum',
 199  			'POOL.Difficulty Rejected' => 'sum',
 200  			'STATS.Times Sent' => 'sum',
 201  			'STATS.Bytes Sent' => 'sum',
 202  			'STATS.Net Bytes Sent' => 'sum',
 203  			'STATS.Times Recv' => 'sum',
 204  			'STATS.Bytes Recv' => 'sum',
 205  			'STATS.Net Bytes Recv' => 'sum',
 206  			'POOL.Accepted' => 'sum'),
 207  	'gen' => array('AvShr' =>
 208  				'round(POOL.Difficulty Accepted/'.
 209  					'max(POOL.Accepted,1)*100)/100'),
 210  	'having' => array(array('STATS.Bytes Recv', '>', 0)))
 211  );
 212  #
 213  $devnotpage = array(
 214   'DATE' => null,
 215   'RIGS' => null,
 216   'DEVS+NOTIFY' => array('DEVS.Name=Name', 'DEVS.ID=ID',
 217  			'DEVS.Temperature=Temp', 'DEVS.MHS av=MHS av',
 218  			'DEVS.Difficulty Accepted=DiffA',
 219  			'DEVS.Difficulty Rejected=DiffR',
 220  			'NOTIFY.Last Not Well=Last Not Well'));
 221  $devnotsum = array(
 222   'DEVS+NOTIFY' => array('DEVS.MHS av', 'DEVS.Difficulty Accepted',
 223  			'DEVS.Difficulty Rejected'));
 224  #
 225  $devdetpage = array(
 226   'DATE' => null,
 227   'RIGS' => null,
 228   'DEVS+DEVDETAILS' => array('DEVS.Name=Name', 'DEVS.ID=ID',
 229  				'DEVS.Temperature=Temp',
 230  				'DEVS.MHS av=MHS av',
 231  				'DEVS.Difficulty Accepted=DiffA',
 232  				'DEVS.Difficulty Rejected=DiffR',
 233  				'DEVDETAILS.Device Path=Device'));
 234  $devdetsum = array(
 235   'DEVS+DEVDETAILS' => array('DEVS.MHS av', 'DEVS.Difficulty Accepted',
 236  				'DEVS.Difficulty Rejected'));
 237  #
 238  $protopage = array(
 239   'DATE' => null,
 240   'RIGS' => null,
 241   'CONFIG' => array('ASC Count=ASCs', 'PGA Count=PGAs', 'Pool Count=Pools',
 242  			'Strategy', 'Device Code', 'OS', 'Failover-Only'),
 243   'SUMMARY' => array('Elapsed', 'MHS av', 'Found Blocks=Blks',
 244  			'Difficulty Accepted=Diff Acc',
 245  			'Difficulty Rejected=Diff Rej',
 246  			'Hardware Errors=HW Errs',
 247  			'Network Blocks=Net Blks', 'Utility', 'Work Utility'),
 248   'POOL+STATS' => array('STATS.ID=ID', 'POOL.URL=URL', 'POOL.Accepted=Acc',
 249  			'POOL.Difficulty Accepted=DiffA',
 250  			'POOL.Difficulty Rejected=DiffR', 'POOL.Has GBT=GBT',
 251  			'STATS.Max Diff=Max Work Diff',
 252  			'STATS.Times Sent=#Sent', 'STATS.Bytes Sent=Byte Sent',
 253  			'STATS.Net Bytes Sent=Net Sent',
 254  			'STATS.Times Recv=#Recv',
 255  			'STATS.Bytes Recv=Byte Recv',
 256  			'STATS.Net Bytes Recv=Net Recv'));
 257  $protosum = array(
 258   'SUMMARY' => array('MHS av', 'Found Blocks', 'Difficulty Accepted',
 259  			'Difficulty Rejected', 'Hardware Errors',
 260  			'Utility', 'Work Utility'),
 261   'POOL+STATS' => array('POOL.Accepted', 'POOL.Difficulty Accepted',
 262  			'POOL.Difficulty Rejected',
 263  			'STATS.Times Sent', 'STATS.Bytes Sent',
 264  			'STATS.Net Bytes Sent', 'STATS.Times Recv',
 265  			'STATS.Bytes Recv', 'STATS.Net Bytes Recv'));
 266  $protoext = array(
 267   'POOL+STATS' => array(
 268  	'where' => null,
 269  	'group' => array('POOL.URL', 'POOL.Has GBT'),
 270  	'calc' => array('POOL.Accepted' => 'sum',
 271  			'POOL.Difficulty Accepted' => 'sum',
 272  			'POOL.Difficulty Rejected' => 'sum',
 273  			'STATS.Max Diff' => 'max',
 274  			'STATS.Times Sent' => 'sum',
 275  			'STATS.Bytes Sent' => 'sum',
 276  			'STATS.Net Bytes Sent' => 'sum',
 277  			'STATS.Times Recv' => 'sum',
 278  			'STATS.Bytes Recv' => 'sum',
 279  			'STATS.Net Bytes Recv' => 'sum'),
 280  	'having' => array(array('STATS.Bytes Recv', '>', 0)))
 281  );
 282  #
 283  # If 'gen' isn't enabled, the 'GEN' fields won't show but
 284  # where present, will be replaced with the ||SUMMARY fields
 285  $kanogenpage = array(
 286   'DATE' => null,
 287   'RIGS' => null,
 288   'SUMMARY+COIN' => array('SUMMARY.Elapsed=Elapsed',
 289  			'GEN.Mined=Block%', 'GEN.GHS Acc=GH/s Acc',
 290  			'GEN.GHS av=GH/s av||SUMMARY.MHS av=MHS av',
 291  			'GEN.GHS 5m=GH/s 5m||SUMMARY.MHS 5m=MHS 5m',
 292  			'GEN.GHS WU=GH/s WU||SUMMARY.Work Utility=WU',
 293  			'SUMMARY.Found Blocks=Blks',
 294  			'SUMMARY.Difficulty Accepted=DiffA',
 295  			'SUMMARY.Difficulty Rejected=DiffR',
 296  			'SUMMARY.Hardware Errors=HW',
 297  			'SUMMARY.Difficulty Stale=DiffS',
 298  			'SUMMARY.Best Share=Best Share',
 299  			'SUMMARY.Device Hardware%=Dev HW%',
 300  			'SUMMARY.Device Rejected%=Dev Rej%',
 301  			'SUMMARY.Pool Rejected%=Pool Rej%',
 302  			'SUMMARY.Pool Stale%=Pool Stale%'),
 303   'POOL' => array('URL', 'Diff1 Shares=Diff Work',
 304  			'Difficulty Accepted=DiffA',
 305  			'Difficulty Rejected=DiffR',
 306  			'Difficulty Stale=DiffS',
 307  			'Best Share', 'GEN.Acc=Pool Acc%', 'GEN.Rej=Pool Rej%')
 308  );
 309  # sum should list all fields seperately including GEN/BGEN || replacements
 310  $kanogensum = array(
 311   'SUMMARY+COIN' => array('GEN.Mined', 'GEN.GHS Acc', 'GEN.GHS av',
 312  			'GEN.GHS 5m', 'GEN.GHS WU',
 313  			'SUMMARY.MHS av', 'SUMMARY.MHS 5m',
 314  			'SUMMARY.Work Utility',
 315  			'SUMMARY.Found Blocks',
 316  			'SUMMARY.Difficulty Accepted',
 317  			'SUMMARY.Difficulty Rejected',
 318  			'SUMMARY.Hardware Errors',
 319  			'SUMMARY.Difficulty Stale'),
 320   'POOL' => array('Diff1 Shares', 'Difficulty Accepted',
 321  			'Difficulty Rejected', 'Difficulty Stale')
 322  );
 323  # 'where', 'calc' and 'having' should list GEN/BGEN || replacements seperately
 324  # 'group' must use the 'name1||name2' format for GEN/BGEN fields
 325  $kanogenext = array(
 326   'SUMMARY+COIN' => array(
 327    'gen' => array('GHS Acc' =>
 328  			'round(pow(2,32) * SUMMARY.Difficulty Accepted / '.
 329  				'SUMMARY.Elapsed / 10000000) / 100',
 330  		'Mined' =>
 331  			'SUMMARY.Elapsed * SUMMARY.Work Utility / 60 / '.
 332  				'COIN.Network Difficulty',
 333  		'GHS av' =>
 334  			'SUMMARY.MHS av / 1000.0',
 335  		'GHS 5m' =>
 336  			'SUMMARY.MHS 5m / 1000.0',
 337  		'GHS WU' =>
 338  			'round(pow(2,32) * SUMMARY.Work Utility / 60 / '.
 339  				'10000000 ) / 100')),
 340   'POOL' => array(
 341    'group' => array('URL'),
 342    'calc' => array('Diff1 Shares' => 'sum', 'Difficulty Accepted' => 'sum',
 343  			'Difficulty Rejected' => 'sum',
 344  			'Difficulty Stale' => 'sum', 'Best Share' => 'max'),
 345    'gen' => array('Rej' => 'Difficulty Rejected / '.
 346  				'max(1,Difficulty Accepted+Difficulty Rejected)',
 347  		'Acc' => 'Difficulty Accepted / '.
 348  				'max(1,Difficulty Accepted+Difficulty Rejected)'))
 349  );
 350  #
 351  $syspage = array(
 352   'DATE' => null,
 353   'RIGS' => null,
 354   'SUMMARY' => array('#', 'Elapsed', 'MHS av', 'MHS 5m', 'Found Blocks=Blks',
 355  			'Difficulty Accepted=DiffA',
 356  			'Difficulty Rejected=DiffR',
 357  			'Difficulty Stale=DiffS', 'Hardware Errors=HW',
 358  			'Work Utility', 'Network Blocks=Net Blks', 'Total MH',
 359  			'Best Share', 'Device Hardware%=Dev HW%',
 360  			'Device Rejected%=Dev Rej%',
 361  			'Pool Rejected%=Pool Rej%', 'Pool Stale%',
 362  			'Last getwork'),
 363   'DEVS' => array('#', 'ID', 'Name', 'ASC', 'Device Elapsed', 'Enabled',
 364  			'Status', 'No Device', 'Temperature=Temp',
 365  			'MHS av', 'MHS 5s', 'MHS 5m', 'Diff1 Work',
 366  			'Difficulty Accepted=DiffA',
 367  			'Difficulty Rejected=DiffR',
 368  			'Hardware Errors=HW', 'Work Utility',
 369  			'Last Valid Work', 'Last Share Pool',
 370  			'Last Share Time', 'Total MH',
 371  			'Device Hardware%=Dev HW%',
 372  			'Device Rejected%=Dev Rej%'),
 373   'POOL' => array('POOL', 'URL', 'Status', 'Priority', 'Quota',
 374  			'Getworks', 'Diff1 Shares',
 375  			'Difficulty Accepted=DiffA',
 376  			'Difficulty Rejected=DiffR',
 377  			'Difficulty Stale=DiffS',
 378  			'Last Share Difficulty',
 379  			'Last Share Time',
 380  			'Best Share', 'Pool Rejected%=Pool Rej%',
 381  			'Pool Stale%')
 382  );
 383  $syssum = array(
 384   'SUMMARY' => array('MHS av', 'MHS 5m', 'Found Blocks',
 385  			'Difficulty Accepted', 'Difficulty Rejected',
 386  			'Difficulty Stale', 'Hardware Errors',
 387  			'Work Utility', 'Total MH'),
 388   'DEVS' => array('MHS av', 'MHS 5s', 'MHS 5m', 'Diff1 Work',
 389  			'Difficulty Accepted', 'Difficulty Rejected',
 390  			'Hardware Errors', 'Total MH'),
 391   'POOL' => array('Getworks', 'Diff1 Shares', 'Difficulty Accepted',
 392  			'Difficulty Rejected', 'Difficulty Stale')
 393  );
 394  #
 395  # $customsummarypages is an array of these Custom Summary Pages
 396  # that you can override in myminer.php
 397  # It can be 'Name' => 1 with 'Name' in any of $user_pages or $sys_pages
 398  # and it can be a fully defined 'Name' => array(...) like in $sys_pages below
 399  $customsummarypages = array(
 400   'Kano' => 1,
 401   'Mobile' => 1,
 402   'Stats' => 1,
 403   'Pools' => 1
 404  );
 405  #
 406  # $user_pages are the myminer.php definable version of $sys_pages
 407  # It should contain a set of 'Name' => array(...) like in $sys_pages
 408  # that $customsummarypages can refer to by 'Name'
 409  # If a 'Name' is in both $user_pages and $sys_pages, then the one
 410  # in $user_pages will override the one in $sys_pages
 411  $user_pages = array();
 412  #
 413  $here = $_SERVER['PHP_SELF'];
 414  #
 415  global $tablebegin, $tableend, $warnfont, $warnoff, $dfmt;
 416  #
 417  $tablebegin = '<tr><td><table border=1 cellpadding=5 cellspacing=0>';
 418  $tableend = '</table></td></tr>';
 419  $warnfont = '<font color=red><b>';
 420  $warnoff = '</b></font>';
 421  $dfmt = 'H:i:s j-M-Y \U\T\CP';
 422  #
 423  $miner_font_family = 'Verdana, Arial, sans-serif, sans';
 424  $miner_font_size = '13pt';
 425  #
 426  $bad_font_family = '"Times New Roman", Times, serif';
 427  $bad_font_size = '18pt';
 428  #
 429  # List of css names to add to the css style object
 430  #	e.g. array('td.cool' => false);
 431  # true/false to not include the default $miner_font
 432  # The css name/value pairs must be defined in $colouroverride below
 433  $add_css_names = array();
 434  #
 435  # Edit this or redefine it in myminer.php to change the colour scheme
 436  # See $colourtable below for the list of names
 437  $colouroverride = array();
 438  #
 439  # Where to place the buttons: 'top' 'bot' 'both'
 440  #  anything else means don't show them - case sensitive
 441  $placebuttons = 'top';
 442  #
 443  # This below allows you to put your own settings into a seperate file
 444  # so you don't need to update miner.php with your preferred settings
 445  # every time a new version is released
 446  # Just create the file 'myminer.php' in the same directory as
 447  # 'miner.php' - and put your own settings in there
 448  if (file_exists('myminer.php'))
 449   include_once('myminer.php');
 450  #
 451  # This is the system default that must always contain all necessary
 452  # colours so it must be a constant
 453  # You can override these values with $colouroverride
 454  # The only one missing is $warnfont
 455  # - which you can override directly anyway
 456  global $colourtable;
 457  $colourtable = array(
 458  	'body bgcolor'		=> '#ecffff',
 459  	'td color'		=> 'blue',
 460  	'td.two color'		=> 'blue',
 461  	'td.two background'	=> '#ecffff',
 462  	'td.h color'		=> 'blue',
 463  	'td.h background'	=> '#c4ffff',
 464  	'td.err color'		=> 'black',
 465  	'td.err background'	=> '#ff3050',
 466  	'td.bad color'		=> 'black',
 467  	'td.bad background'	=> '#ff3050',
 468  	'td.warn color'		=> 'black',
 469  	'td.warn background'	=> '#ffb050',
 470  	'td.sta color'		=> 'green',
 471  	'td.tot color'		=> 'blue',
 472  	'td.tot background'	=> '#fff8f2',
 473  	'td.lst color'		=> 'blue',
 474  	'td.lst background'	=> '#ffffdd',
 475  	'td.hi color'		=> 'blue',
 476  	'td.hi background'	=> '#f6ffff',
 477  	'td.lo color'		=> 'blue',
 478  	'td.lo background'	=> '#deffff'
 479  );
 480  #
 481  # A list of system default summary pages (defined further above)
 482  # that you can use by 'Name' in $customsummarypages
 483  global $sys_pages;
 484  $sys_pages = array(
 485   'Mobile' => array($mobilepage, $mobilesum),
 486   'Stats' => array($statspage, $statssum),
 487   'Pools' => array($poolspage, $poolssum, $poolsext),
 488   'DevNot' => array($devnotpage, $devnotsum),
 489   'DevDet' => array($devdetpage, $devdetsum),
 490   'Proto' => array($protopage, $protosum, $protoext),
 491   'Kano' => array($kanogenpage, $kanogensum, $kanogenext),
 492   'Summary' => array($syspage, $syssum)
 493  );
 494  #
 495  # Don't touch these 2
 496  $miner = null;
 497  $port = null;
 498  #
 499  global $rigips;
 500  $rigips = array();
 501  #
 502  # Ensure it is only ever shown once
 503  global $showndate;
 504  $showndate = false;
 505  #
 506  global $rownum;
 507  $rownum = 0;
 508  #
 509  // Login
 510  global $ses;
 511  $ses = 'rutroh';
 512  #
 513  function getcsp($name, $systempage = false)
 514  {
 515   global $customsummarypages, $user_pages, $sys_pages;
 516  
 517   if ($systempage === false)
 518   {
 519  	if (!isset($customsummarypages[$name]))
 520  		return false;
 521  
 522  	$csp = $customsummarypages[$name];
 523  	if (is_array($csp))
 524  	{
 525  		if (count($csp) < 2 || count($csp) > 3)
 526  			return false;
 527  		else
 528  			return $csp;
 529  	}
 530   }
 531  
 532   if (isset($user_pages[$name]))
 533   {
 534  	$csp = $user_pages[$name];
 535  	if (!is_array($csp) || count($csp) < 2 || count($csp) > 3)
 536  		return false;
 537  	else
 538  		return $csp;
 539   }
 540  
 541   if (isset($sys_pages[$name]))
 542   {
 543  	$csp = $sys_pages[$name];
 544  	if (!is_array($csp) || count($csp) < 2 || count($csp) > 3)
 545  		return false;
 546  	else
 547  		return $csp;
 548   }
 549  
 550   return false;
 551  }
 552  #
 553  function degenfields(&$sec, $name, $fields)
 554  {
 555   global $allowgen;
 556  
 557   if (!is_array($fields))
 558  	return;
 559  
 560   foreach ($fields as $num => $fld)
 561  	if (substr($fld, 0, 5) == 'BGEN.' || substr($fld, 0, 4) == 'GEN.')
 562  	{
 563  		$opts = explode('||', $fld, 2);
 564  		if ($allowgen)
 565  		{
 566  			if (count($opts) > 1)
 567  				$sec[$name][$num] = $opts[0];
 568  		}
 569  		else
 570  		{
 571  			if (count($opts) > 1)
 572  				$sec[$name][$num] = $opts[1];
 573  			else
 574  				unset($sec[$name][$num]);
 575  		}
 576  	}
 577  }
 578  #
 579  # Allow BGEN/GEN fields to have a '||' replacement when gen is disabled
 580  # N.B. if gen is disabled and all page fields are GBEN/GEN without '||' then
 581  # the table will disappear
 582  # Replacements can be in the page fields and then also the ext group fields
 583  # All other $csp sections should list both separately
 584  function degen(&$csp)
 585  {
 586   $page = 0;
 587   if (isset($csp[$page]) && is_array($csp[$page]))
 588  	foreach ($csp[$page] as $sec => $fields)
 589  		degenfields($csp[$page], $sec, $fields);
 590  
 591   $ext = 2;
 592   if (isset($csp[$ext]) && is_array($csp[$ext]))
 593  	foreach ($csp[$ext] as $sec => $types)
 594  		if (is_array($types) && isset($types['group']))
 595  			degenfields($types, 'group', $types['group']);
 596  }
 597  #
 598  function getcss($cssname, $dom = false)
 599  {
 600   global $colourtable, $colouroverride;
 601  
 602   $css = '';
 603   foreach ($colourtable as $cssdata => $value)
 604   {
 605  	$cssobj = explode(' ', $cssdata, 2);
 606  	if ($cssobj[0] == $cssname)
 607  	{
 608  		if (isset($colouroverride[$cssdata]))
 609  			$value = $colouroverride[$cssdata];
 610  
 611  		if ($dom == true)
 612  			$css .= ' '.$cssobj[1].'='.$value;
 613  		else
 614  			$css .= $cssobj[1].':'.$value.'; ';
 615  	}
 616   }
 617   return $css;
 618  }
 619  #
 620  function getdom($domname)
 621  {
 622   return getcss($domname, true);
 623  }
 624  #
 625  # N.B. don't call this before calling htmlhead()
 626  function php_pr($cmd)
 627  {
 628   global $here, $autorefresh;
 629  
 630   return "$here?ref=$autorefresh$cmd";
 631  }
 632  #
 633  function htmlhead($mcerr, $checkapi, $rig, $pg = null, $noscript = false)
 634  {
 635   global $doctype, $title, $miner_font_family, $miner_font_size;
 636   global $bad_font_family, $bad_font_size, $add_css_names;
 637   global $error, $readonly, $poolinputs, $here;
 638   global $ignorerefresh, $autorefresh;
 639  
 640   $extraparams = '';
 641   if ($rig != null && $rig != '')
 642  	$extraparams = "&rig=$rig";
 643   else
 644  	if ($pg != null && $pg != '')
 645  		$extraparams = "&pg=$pg";
 646  
 647   if ($ignorerefresh == true || $autorefresh == 0)
 648  	$refreshmeta = '';
 649   else
 650   {
 651  	$url = "$here?ref=$autorefresh$extraparams";
 652  	$refreshmeta = "\n<meta http-equiv='refresh' content='$autorefresh;url=$url'>";
 653   }
 654  
 655   if ($readonly === false && $checkapi === true)
 656   {
 657  	$error = null;
 658  	$access = api($rig, 'privileged');
 659  	if ($error != null
 660  	||  !isset($access['STATUS']['STATUS'])
 661  	||  $access['STATUS']['STATUS'] != 'S')
 662  		$readonly = true;
 663   }
 664   $miner_font = "font-family:$miner_font_family; font-size:$miner_font_size;";
 665   $bad_font = "font-family:$bad_font_family; font-size:$bad_font_size;";
 666  
 667   echo "$doctype<html><head>$refreshmeta
 668  <title>$title</title>
 669  <style type='text/css'>
 670  td { $miner_font ".getcss('td')."}
 671  td.two { $miner_font ".getcss('td.two')."}
 672  td.h { $miner_font ".getcss('td.h')."}
 673  td.err { $miner_font ".getcss('td.err')."}
 674  td.bad { $bad_font ".getcss('td.bad')."}
 675  td.warn { $miner_font ".getcss('td.warn')."}
 676  td.sta { $miner_font ".getcss('td.sta')."}
 677  td.tot { $miner_font ".getcss('td.tot')."}
 678  td.lst { $miner_font ".getcss('td.lst')."}
 679  td.hi { $miner_font ".getcss('td.hi')."}
 680  td.lo { $miner_font ".getcss('td.lo')."}\n";
 681   if (isset($add_css_names))
 682  	foreach ($add_css_names as $css_name => $no_miner_font)
 683  	{
 684  		echo "$css_name { ";
 685  		if ($no_miner_font !== true)
 686  			echo "$miner_font ";
 687  		echo getcss("$css_name")."}\n";
 688  	}
 689   echo "</style>
 690  </head><body".getdom('body').">\n";
 691  if ($noscript === false)
 692  {
 693  echo "<script type='text/javascript'>
 694  function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n";
 695  
 696  if ($ignorerefresh == false)
 697   echo "function prr(a){if(a){v=document.getElementById('refval').value}else{v=0}window.location='$here?ref='+v+'$extraparams'}\n";
 698  
 699   if ($readonly === false && $checkapi === true)
 700   {
 701  echo "function prc(a,m){pr('&arg='+a,m)}
 702  function prs(a,r){var c=a.substr(3);var z=c.split('|',2);var m=z[0].substr(0,1).toUpperCase()+z[0].substr(1)+' GPU '+z[1];prc(a+'&rig='+r,m)}
 703  function prs2(a,n,r){var v=document.getElementById('gi'+n).value;var c=a.substr(3);var z=c.split('|',2);var m='Set GPU '+z[1]+' '+z[0].substr(0,1).toUpperCase()+z[0].substr(1)+' to '+v;prc(a+','+v+'&rig='+r,m)}\n";
 704  	if ($poolinputs === true)
 705  		echo "function cbs(s){var t=s.replace(/\\\\/g,'\\\\\\\\'); return t.replace(/,/g, '\\\\,')}\nfunction pla(r){var u=document.getElementById('purl').value;var w=document.getElementById('pwork').value;var p=document.getElementById('ppass').value;pr('&rig='+r+'&arg=addpool|'+cbs(u)+','+cbs(w)+','+cbs(p),'Add Pool '+u)}\nfunction psp(r){var p=document.getElementById('prio').value;pr('&rig='+r+'&arg=poolpriority|'+p,'Set Pool Priorities to '+p)}\n";
 706   }
 707  echo "</script>\n";
 708  }
 709  ?>
 710  <table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'>
 711  <tr><td align=center valign=top>
 712  <table border=0 cellpadding=4 cellspacing=0 summary='Mine'>
 713  <?php
 714   echo $mcerr;
 715  }
 716  #
 717  function minhead($mcerr = '')
 718  {
 719   global $readonly;
 720   $readonly = true;
 721   htmlhead($mcerr, false, null, null, true);
 722  }
 723  #
 724  global $haderror, $error;
 725  $haderror = false;
 726  $error = null;
 727  #
 728  function mcastrigs()
 729  {
 730   global $rigs, $mcastexpect, $mcastaddr, $mcastport, $mcastcode;
 731   global $mcastlistport, $mcasttimeout, $mcastretries, $error;
 732  
 733   $listname = "0.0.0.0";
 734  
 735   $rigs = array();
 736  
 737   $rep_soc = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
 738   if ($rep_soc === false || $rep_soc == null)
 739   {
 740  	$msg = "ERR: mcast listen socket create(UDP) failed";
 741  	if ($rigipsecurity === false)
 742  	{
 743  		$error = socket_strerror(socket_last_error());
 744  		$error = "$msg '$error'\n";
 745  	}
 746  	else
 747  		$error = "$msg\n";
 748  
 749  	return;
 750   }
 751  
 752   $res = socket_bind($rep_soc, $listname, $mcastlistport);
 753   if ($res === false)
 754   {
 755  	$msg1 = "ERR: mcast listen socket bind(";
 756  	$msg2 = ") failed";
 757  	if ($rigipsecurity === false)
 758  	{
 759  		$error = socket_strerror(socket_last_error());
 760  		$error = "$msg1$listname,$mcastlistport$msg2 '$error'\n";
 761  	}
 762  	else
 763  		$error = "$msg1$msg2\n";
 764  
 765  	socket_close($rep_soc);
 766  	return;
 767   }
 768  
 769   $retries = $mcastretries;
 770   $doretry = ($retries > 0);
 771   do
 772   {
 773  	$mcast_soc = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
 774  	if ($mcast_soc === false || $mcast_soc == null)
 775  	{
 776  		$msg = "ERR: mcast send socket create(UDP) failed";
 777  		if ($rigipsecurity === false)
 778  		{
 779  			$error = socket_strerror(socket_last_error());
 780  			$error = "$msg '$error'\n";
 781  		}
 782  		else
 783  			$error = "$msg\n";
 784  
 785  		socket_close($rep_soc);
 786  		return;
 787  	}
 788  
 789  	$buf = "cgminer-$mcastcode-$mcastlistport";
 790  	socket_sendto($mcast_soc, $buf, strlen($buf), 0, $mcastaddr, $mcastport);
 791  	socket_close($mcast_soc);
 792  
 793  	$stt = microtime(true);
 794  	while (true)
 795  	{
 796  		$got = @socket_recvfrom($rep_soc, $buf, 32, MSG_DONTWAIT, $ip, $p);
 797  		if ($got !== false && $got > 0)
 798  		{
 799  			$ans = explode('-', $buf, 4);
 800  			if (count($ans) >= 3 && $ans[0] == 'cgm' && $ans[1] == 'FTW')
 801  			{
 802  				$rp = intval($ans[2]);
 803  
 804  				if (count($ans) > 3)
 805  					$mdes = str_replace("\0", '', $ans[3]);
 806  				else
 807  					$mdes = '';
 808  
 809  				if (strlen($mdes) > 0)
 810  					$rig = "$ip:$rp:$mdes";
 811  				else
 812  					$rig = "$ip:$rp";
 813  
 814  				if (!in_array($rig, $rigs))
 815  					$rigs[] = $rig;
 816  			}
 817  		}
 818  		if ((microtime(true) - $stt) >= $mcasttimeout)
 819  			break;
 820  
 821  		usleep(100000);
 822  	}
 823  
 824  	if ($mcastexpect > 0 && count($rigs) >= $mcastexpect)
 825  		$doretry = false;
 826  
 827   } while ($doretry && --$retries > 0);
 828  
 829   socket_close($rep_soc);
 830  }
 831  #
 832  function getrigs()
 833  {
 834   global $rigs;
 835  
 836   mcastrigs();
 837  
 838   sort($rigs);
 839  }
 840  #
 841  function getsock($rig, $addr, $port)
 842  {
 843   global $rigport, $rigips, $rignames, $rigipsecurity;
 844   global $haderror, $error, $socksndtimeoutsec, $sockrcvtimeoutsec;
 845  
 846   $port = trim($port);
 847   if (strlen($port) == 0)
 848  	$port = $rigport;
 849   $error = null;
 850   $socket = null;
 851   $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
 852   if ($socket === false || $socket === null)
 853   {
 854  	$haderror = true;
 855  	if ($rigipsecurity === false)
 856  	{
 857  		$error = socket_strerror(socket_last_error());
 858  		$msg = "socket create(TCP) failed";
 859  		$error = "ERR: $msg '$error'\n";
 860  	}
 861  	else
 862  		$error = "ERR: socket create(TCP) failed\n";
 863  
 864  	return null;
 865   }
 866  
 867   // Ignore if this fails since the socket connect may work anyway
 868   //  and nothing is gained by aborting if the option cannot be set
 869   //  since we don't know in advance if it can connect
 870   socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $socksndtimeoutsec, 'usec' => 0));
 871   socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $sockrcvtimeoutsec, 'usec' => 0));
 872  
 873   $res = socket_connect($socket, $addr, $port);
 874   if ($res === false)
 875   {
 876  	$haderror = true;
 877  	if ($rigipsecurity === false)
 878  	{
 879  		$error = socket_strerror(socket_last_error());
 880  		$msg = "socket connect($addr,$port) failed";
 881  		$error = "ERR: $msg '$error'\n";
 882  	}
 883  	else
 884  		$error = "ERR: socket connect($rig) failed\n";
 885  
 886  	socket_close($socket);
 887  	return null;
 888   }
 889   if ($rignames !== false && !isset($rigips[$addr]))
 890  	if (socket_getpeername($socket, $ip) == true)
 891  		$rigips[$addr] = $ip;
 892   return $socket;
 893  }
 894  #
 895  function readsockline($socket)
 896  {
 897   $line = '';
 898   while (true)
 899   {
 900  	$byte = socket_read($socket, 1);
 901  	if ($byte === false || $byte === '')
 902  		break;
 903  	if ($byte === "\0")
 904  		break;
 905  	$line .= $byte;
 906   }
 907   return $line;
 908  }
 909  #
 910  function api_convert_escape($str)
 911  {
 912   $res = '';
 913   $len = strlen($str);
 914   for ($i = 0; $i < $len; $i++)
 915   {
 916  	$ch = substr($str, $i, 1);
 917  	if ($ch != '\\' || $i == ($len-1))
 918  		$res .= $ch;
 919  	else
 920  	{
 921  		$i++;
 922  		$ch = substr($str, $i, 1);
 923  		switch ($ch)
 924  		{
 925  		case '|':
 926  			$res .= "\1";
 927  			break;
 928  		case '\\':
 929  			$res .= "\2";
 930  			break;
 931  		case '=':
 932  			$res .= "\3";
 933  			break;
 934  		case ',':
 935  			$res .= "\4";
 936  			break;
 937  		default:
 938  			$res .= $ch;
 939  		}
 940  	}
 941   }
 942   return $res;
 943  }
 944  #
 945  function revert($str)
 946  {
 947   return str_replace(array("\1", "\2", "\3", "\4"), array("|", "\\", "=", ","), $str);
 948  }
 949  #
 950  function api($rig, $cmd)
 951  {
 952   global $haderror, $error;
 953   global $miner, $port, $hidefields;
 954  
 955   $socket = getsock($rig, $miner, $port);
 956   if ($socket != null)
 957   {
 958  	socket_write($socket, $cmd, strlen($cmd));
 959  	$line = readsockline($socket);
 960  	socket_close($socket);
 961  
 962  	if (strlen($line) == 0)
 963  	{
 964  		$haderror = true;
 965  		$error = "WARN: '$cmd' returned nothing\n";
 966  		return $line;
 967  	}
 968  
 969  #	print "$cmd returned '$line'\n";
 970  
 971  	$line = api_convert_escape($line);
 972  
 973  	$data = array();
 974  
 975  	$objs = explode('|', $line);
 976  	foreach ($objs as $obj)
 977  	{
 978  		if (strlen($obj) > 0)
 979  		{
 980  			$items = explode(',', $obj);
 981  			$item = $items[0];
 982  			$id = explode('=', $items[0], 2);
 983  			if (count($id) == 1 or !ctype_digit($id[1]))
 984  				$name = $id[0];
 985  			else
 986  				$name = $id[0].$id[1];
 987  
 988  			if (strlen($name) == 0)
 989  				$name = 'null';
 990  
 991  			$sectionname = preg_replace('/\d/', '', $name);
 992  
 993  			if (isset($data[$name]))
 994  			{
 995  				$num = 1;
 996  				while (isset($data[$name.$num]))
 997  					$num++;
 998  				$name .= $num;
 999  			}
1000  
1001  			$counter = 0;
1002  			foreach ($items as $item)
1003  			{
1004  				$id = explode('=', $item, 2);
1005  
1006  				if (isset($hidefields[$sectionname.'.'.$id[0]]))
1007  					continue;
1008  
1009  				if (count($id) == 2)
1010  					$data[$name][$id[0]] = revert($id[1]);
1011  				else
1012  					$data[$name][$counter] = $id[0];
1013  
1014  				$counter++;
1015  			}
1016  		}
1017  	}
1018  	return $data;
1019   }
1020   return null;
1021  }
1022  #
1023  function getparam($name, $both = false)
1024  {
1025   $a = null;
1026   if (isset($_POST[$name]))
1027  	$a = $_POST[$name];
1028  
1029   if (($both === true) and ($a === null))
1030   {
1031  	if (isset($_GET[$name]))
1032  		$a = $_GET[$name];
1033   }
1034  
1035   if ($a == '' || $a == null)
1036  	return null;
1037  
1038   // limit to 1K just to be safe
1039   return substr($a, 0, 1024);
1040  }
1041  #
1042  function newtable()
1043  {
1044   global $tablebegin, $rownum;
1045   echo $tablebegin;
1046   $rownum = 0;
1047  }
1048  #
1049  function newrow()
1050  {
1051   echo '<tr>';
1052  }
1053  #
1054  function othrow($row)
1055  {
1056   return "<tr>$row</tr>";
1057  }
1058  #
1059  function otherrow($row)
1060  {
1061   echo othrow($row);
1062  }
1063  #
1064  function endrow()
1065  {
1066   global $rownum;
1067   echo '</tr>';
1068   $rownum++;
1069  }
1070  #
1071  function endtable()
1072  {
1073   global $tableend;
1074   echo $tableend;
1075  }
1076  #
1077  function classlastshare($when, $alldata, $warnclass, $errorclass)
1078  {
1079   global $checklastshare;
1080  
1081   if ($checklastshare === false)
1082  	return '';
1083  
1084   if ($when == 0)
1085  	return '';
1086  
1087   if (!isset($alldata['MHS av']))
1088  	return '';
1089  
1090   if ($alldata['MHS av'] == 0)
1091  	return '';
1092  
1093   if (!isset($alldata['Last Share Time']))
1094  	return '';
1095  
1096   if (!isset($alldata['Last Share Difficulty']))
1097  	return '';
1098  
1099   $expected = pow(2, 32) / ($alldata['MHS av'] * pow(10, 6));
1100  
1101   // If the share difficulty changes while waiting on a share,
1102   // this calculation will of course be incorrect
1103   $expected *= $alldata['Last Share Difficulty'];
1104  
1105   $howlong = $when - $alldata['Last Share Time'];
1106   if ($howlong < 1)
1107  	$howlong = 1;
1108  
1109   if ($howlong > ($expected * 12))
1110  	return $errorclass;
1111  
1112   if ($howlong > ($expected * 8))
1113  	return $warnclass;
1114  
1115   return '';
1116  }
1117  #
1118  function endzero($num)
1119  {
1120   $rep = preg_replace('/0*$/', '', $num);
1121   if ($rep === '')
1122  	$rep = '0';
1123   return $rep;
1124  }
1125  #
1126  function fmt($section, $name, $value, $when, $alldata, $cf = NULL)
1127  {
1128   global $dfmt, $rownum;
1129  
1130   if ($alldata == null)
1131  	$alldata = array();
1132  
1133   $errorclass = 'err';
1134   $warnclass = 'warn';
1135   $lstclass = 'lst';
1136   $hiclass = 'hi';
1137   $loclass = 'lo';
1138   $c2class = 'two';
1139   $totclass = 'tot';
1140   $b = '&nbsp;';
1141  
1142   $class = '';
1143  
1144   $nams = explode('.', $name);
1145   if (count($nams) > 1)
1146  	$name = $nams[count($nams)-1];
1147  
1148   $done = false;
1149   if ($value === null)
1150   {
1151  	$ret = $b;
1152  	$done = true;
1153   }
1154   else
1155  	if ($cf != NULL and function_exists($cf))
1156  	{
1157  		list($ret, $class) = $cf($section, $name, $value, $when, $alldata,
1158  					   $warnclass, $errorclass, $hiclass, $loclass, $totclass);
1159  		if ($ret !== '')
1160  			$done = true;
1161  	}
1162  
1163   if ($done === false)
1164   {
1165  	$ret = $value;
1166  	/*
1167  	 * To speed up the PHP, the case statement is just $name
1168  	 * It used to be $section.'.'.$name
1169  	 * If any names clash, the case code will need to check the value of
1170  	 * $section to resolve the clash - as with 'Last Share Time' below
1171  	 * If the code picks up a field that you wish to format differently,
1172  	 * then you'll need a customsummarypage 'fmt' extension
1173  	 */
1174  	switch ($name)
1175  	{
1176  	case '0':
1177  		break;
1178  	case 'Last Share Time':
1179  		if ($section == 'total')
1180  			break;
1181  		if ($section == 'POOL')
1182  		{
1183  			if ($value == 0)
1184  				$ret = 'Never';
1185  			else
1186  				$ret = date('H:i:s d-M', $value);
1187  		}
1188  		else
1189  		{
1190  			if ($value == 0
1191  			||  (isset($alldata['Last Share Pool']) && $alldata['Last Share Pool'] == -1))
1192  			{
1193  				$ret = 'Never';
1194  				$class = $warnclass;
1195  			}
1196  			else
1197  			{
1198  				$ret = date('H:i:s', $value);
1199  				$class = classlastshare($when, $alldata, $warnclass, $errorclass);
1200  			}
1201  		}
1202  		break;
1203  	case 'Last getwork':
1204  	case 'Last Valid Work':
1205  		if ($section == 'total')
1206  			break;
1207  		if ($value == 0)
1208  			$ret = 'Never';
1209  		else
1210  			$ret = ($value - $when) . 's';
1211  		break;
1212  	case 'Last Share Pool':
1213  		if ($section == 'total')
1214  			break;
1215  		if ($value == -1)
1216  		{
1217  			$ret = 'None';
1218  			$class = $warnclass;
1219  		}
1220  		break;
1221  	case 'Elapsed':
1222  	case 'Device Elapsed':
1223  		if ($section == 'total')
1224  			break;
1225  		$s = $value % 60;
1226  		$value -= $s;
1227  		$value /= 60;
1228  		if ($value == 0)
1229  			$ret = $s.'s';
1230  		else
1231  		{
1232  			$m = $value % 60;
1233  			$value -= $m;
1234  			$value /= 60;
1235  			if ($value == 0)
1236  				$ret = sprintf("%dm$b%02ds", $m, $s);
1237  			else
1238  			{
1239  				$h = $value % 24;
1240  				$value -= $h;
1241  				$value /= 24;
1242  				if ($value == 0)
1243  					$ret = sprintf("%dh$b%02dm$b%02ds", $h, $m, $s);
1244  				else
1245  				{
1246  					if ($value == 1)
1247  						$days = '';
1248  					else
1249  						$days = 's';
1250  	
1251  					$ret = sprintf("%dday$days$b%02dh$b%02dm$b%02ds", $value, $h, $m, $s);
1252  				}
1253  			}
1254  		}
1255  		break;
1256  	case 'Last Well':
1257  		if ($section == 'total')
1258  			break;
1259  		if ($value == '0')
1260  		{
1261  			$ret = 'Never';
1262  			$class = $warnclass;
1263  		}
1264  		else
1265  			$ret = date('H:i:s', $value);
1266  		break;
1267  	case 'Last Not Well':
1268  		if ($section == 'total')
1269  			break;
1270  		if ($value == '0')
1271  			$ret = 'Never';
1272  		else
1273  		{
1274  			$ret = date('H:i:s', $value);
1275  			$class = $errorclass;
1276  		}
1277  		break;
1278  	case 'Reason Not Well':
1279  		if ($section == 'total')
1280  			break;
1281  		if ($value != 'None')
1282  			$class = $errorclass;
1283  		break;
1284  	case 'Utility':
1285  		$ret = number_format($value, 2).'/m';
1286  		if ($value == 0)
1287  			$class = $errorclass;
1288  		else
1289  			if (isset($alldata['Difficulty Accepted'])
1290  			&&  isset($alldata['Accepted'])
1291  			&&  isset($alldata['MHS av'])
1292  			&&  ($alldata['Difficulty Accepted'] > 0)
1293  			&&  ($alldata['Accepted'] > 0))
1294  			{
1295  				$expected = 60 * $alldata['MHS av'] * (pow(10, 6) / pow(2, 32));
1296  				if ($expected == 0)
1297  					$expected = 0.000001; // 1 H/s
1298  
1299  				$da = $alldata['Difficulty Accepted'];
1300  				$a = $alldata['Accepted'];
1301  				$expected /= ($da / $a);
1302  
1303  				$ratio = $value / $expected;
1304  				if ($ratio < 0.9)
1305  					$class = $loclass;
1306  				else
1307  					if ($ratio > 1.1)
1308  						$class = $hiclass;
1309  			}
1310  		break;
1311  	case 'Work Utility':
1312  		$ret = number_format($value, 2).'/m';
1313  		break;
1314  	case 'Temperature':
1315  		if ($section == 'total')
1316  			break;
1317  		$ret = $value.'&deg;C';
1318  		if ($value == 0)
1319  			$ret = '&nbsp;';
1320  		break;
1321  	case 'Fan Percent':
1322  		if ($section == 'total')
1323  			break;
1324  		if ($value == 0)
1325  			$class = $warnclass;
1326  		else
1327  		{
1328  			if ($value == 100)
1329  				$class = $errorclass;
1330  			else
1331  				if ($value > 85)
1332  					$class = $warnclass;
1333  		}
1334  		break;
1335  	case 'Fan Speed':
1336  		if ($section == 'total')
1337  			break;
1338  		if ($value == 0)
1339  			$class = $warnclass;
1340  		else
1341  			if (isset($alldata['Fan Percent']))
1342  			{
1343  				$test = $alldata['Fan Percent'];
1344  				if ($test == 100)
1345  					$class = $errorclass;
1346  				else
1347  					if ($test > 85)
1348  						$class = $warnclass;
1349  			}
1350  		break;
1351  	case 'MHS av':
1352  	case 'MHS 5s':
1353  	case 'MHS 1m':
1354  	case 'MHS 5m':
1355  	case 'MHS 15m':
1356  		$parts = explode('.', $value, 2);
1357  		if (count($parts) == 1)
1358  			$dec = '';
1359  		else
1360  			$dec = '.'.$parts[1];
1361  		$ret = number_format((float)$parts[0]).$dec;
1362  
1363  		if ($value == 0)
1364  			$class = $errorclass;
1365  		else
1366  			if (isset($alldata['Difficulty Accepted'])
1367  			&&  isset($alldata['Accepted'])
1368  			&&  isset($alldata['Utility'])
1369  			&&  ($alldata['Difficulty Accepted'] > 0)
1370  			&&  ($alldata['Accepted'] > 0))
1371  			{
1372  				$expected = 60 * $value * (pow(10, 6) / pow(2, 32));
1373  				if ($expected == 0)
1374  					$expected = 0.000001; // 1 H/s
1375  
1376  				$da = $alldata['Difficulty Accepted'];
1377  				$a = $alldata['Accepted'];
1378  				$expected /= ($da / $a);
1379  
1380  				$ratio = $alldata['Utility'] / $expected;
1381  				if ($ratio < 0.9)
1382  					$class = $hiclass;
1383  				else
1384  					if ($ratio > 1.1)
1385  						$class = $loclass;
1386  			}
1387  		break;
1388  	case 'Total MH':
1389  	case 'Getworks':
1390  	case 'Works':
1391  	case 'Accepted':
1392  	case 'Rejected':
1393  	case 'Local Work':
1394  	case 'Discarded':
1395  	case 'Diff1 Shares':
1396  	case 'Diff1 Work':
1397  	case 'Times Sent':
1398  	case 'Bytes Sent':
1399  	case 'Net Bytes Sent':
1400  	case 'Times Recv':
1401  	case 'Bytes Recv':
1402  	case 'Net Bytes Recv':
1403  		$parts = explode('.', $value, 2);
1404  		if (count($parts) == 1)
1405  			$dec = '';
1406  		else
1407  			$dec = '.'.$parts[1];
1408  		$ret = number_format((float)$parts[0]).$dec;
1409  		break;
1410  	case 'Hs':
1411  	case 'W':
1412  	case 'history_time':
1413  	case 'Pool Wait':
1414  	case 'Pool Max':
1415  	case 'Pool Min':
1416  	case 'Pool Av':
1417  	case 'Min Diff':
1418  	case 'Max Diff':
1419  	case 'Work Diff':
1420  		$parts = explode('.', $value, 2);
1421  		if (count($parts) == 1)
1422  			$dec = '';
1423  		else
1424  			$dec = '.'.endzero($parts[1]);
1425  		$ret = number_format((float)$parts[0]).$dec;
1426  		break;
1427  	case 'Status':
1428  		if ($section == 'total')
1429  			break;
1430  		if ($value != 'Alive')
1431  			$class = $errorclass;
1432  		break;
1433  	case 'Enabled':
1434  		if ($section == 'total')
1435  			break;
1436  		if ($value != 'Y')
1437  			$class = $warnclass;
1438  		break;
1439  	case 'No Device':
1440  		if ($section == 'total')
1441  			break;
1442  		if ($value != 'false')
1443  			$class = $errorclass;
1444  		break;
1445  	case 'When':
1446  	case 'Current Block Time':
1447  		if ($section == 'total')
1448  			break;
1449  		$ret = date($dfmt, $value);
1450  		break;
1451  	case 'Last Share Difficulty':
1452  		if ($section == 'total')
1453  			break;
1454  	case 'Difficulty Accepted':
1455  	case 'Difficulty Rejected':
1456  	case 'Difficulty Stale':
1457  		if ($value != '')
1458  			$ret = number_format((float)$value, 2);
1459  		break;
1460  	case 'Device Hardware%':
1461  	case 'Device Rejected%':
1462  	case 'Pool Rejected%':
1463  	case 'Pool Stale%':
1464  		if ($section == 'total')
1465  			break;
1466  		if ($value != '')
1467  			$ret = number_format((float)$value, 2) . '%';
1468  		break;
1469  	case 'Best Share':
1470  		if ($section == 'total')
1471  			break;
1472  	case 'Hardware Errors':
1473  		if ($value != '')
1474  			$ret = number_format((float)$value);
1475  		break;
1476  	// BUTTON.
1477  	case 'Rig':
1478  	case 'Pool':
1479  	// Sample GEN fields
1480  	case 'Mined':
1481  		if ($value != '')
1482  			$ret = number_format((float)$value * 100.0, 3) . '%';
1483  		break;
1484  	case 'Acc':
1485  	case 'Rej':
1486  		if ($value != '')
1487  			$ret = number_format((float)$value * 100.0, 2) . '%';
1488  		break;
1489  	case 'GHS av':
1490  	case 'GHS 5m':
1491  	case 'GHS WU':
1492  	case 'GHS Acc':
1493  		if ($value != '')
1494  			$ret = number_format((float)$value, 2);
1495  		break;
1496  	case 'AvShr':
1497  		if ($section == 'total')
1498  			break;
1499  		if ($value != '')
1500  			$ret = number_format((float)$value, 2);
1501  		if ($value == 0)
1502  			$class = $warnclass;
1503  		break;
1504  	}
1505   }
1506  
1507   if ($section == 'NOTIFY' && substr($name, 0, 1) == '*' && $value != '0')
1508  	$class = $errorclass;
1509  
1510   if ($class == '' && $section != 'POOL')
1511  	$class = classlastshare($when, $alldata, $lstclass, $lstclass);
1512  
1513   if ($class == '' && $section == 'total')
1514  	$class = $totclass;
1515  
1516   if ($class == '' && ($rownum % 2) == 0)
1517  	$class = $c2class;
1518  
1519   if ($ret === '')
1520  	$ret = $b;
1521  
1522   if ($class !== '')
1523  	$class = " class=$class";
1524  
1525   return array($ret, $class);
1526  }
1527  #
1528  global $poolcmd;
1529  $poolcmd = array(	'Switch to'	=> 'switchpool',
1530  			'Enable'	=> 'enablepool',
1531  			'Disable'	=> 'disablepool',
1532  			'Remove'	=> 'removepool' );
1533  #
1534  function showhead($cmd, $values, $justnames = false)
1535  {
1536   global $poolcmd, $readonly;
1537  
1538   newrow();
1539  
1540   foreach ($values as $name => $value)
1541   {
1542  	if ($name == '0' or $name == '')
1543  		$name = '&nbsp;';
1544  	echo "<td valign=bottom class=h>$name</td>";
1545   }
1546  
1547   if ($justnames === false && $cmd == 'pools' && $readonly === false)
1548  	foreach ($poolcmd as $name => $pcmd)
1549  		echo "<td valign=bottom class=h>$name</td>";
1550  
1551   endrow();
1552  }
1553  #
1554  function showdatetime()
1555  {
1556   global $dfmt;
1557  
1558   otherrow('<td class=sta>Date: '.date($dfmt).'</td>');
1559  }
1560  #
1561  global $singlerigsum;
1562  $singlerigsum = array(
1563   'devs' => array('MHS av' => 1, 'MHS 5s' => 1, 'MHS 1m' => 1, 'MHS 5m' => 1,
1564  			'MHS 15m' => 1, 'Accepted' => 1, 'Rejected' => 1,
1565  			'Hardware Errors' => 1, 'Utility' => 1, 'Total MH' => 1,
1566  			'Diff1 Shares' => 1, 'Diff1 Work' => 1,
1567  			'Difficulty Accepted' => 1, 'Difficulty Rejected' => 1),
1568   'pools' => array('Getworks' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Discarded' => 1,
1569  			'Stale' => 1, 'Get Failures' => 1, 'Remote Failures' => 1,
1570  			'Diff1 Shares' => 1, 'Diff1 Work' => 1,
1571  			'Difficulty Accepted' => 1, 'Difficulty Rejected' => 1,
1572  			'Difficulty Stale' => 1),
1573   'notify' => array('*' => 1));
1574  #
1575  function showtotal($total, $when, $oldvalues)
1576  {
1577   global $rigtotals;
1578  
1579   list($showvalue, $class) = fmt('total', '', 'Total:', $when, null);
1580   echo "<td$class align=right>$showvalue</td>";
1581  
1582   $skipfirst = true;
1583   foreach ($oldvalues as $name => $value)
1584   {
1585  	if ($skipfirst === true)
1586  	{
1587  		$skipfirst = false;
1588  		continue;
1589  	}
1590  
1591  	if (isset($total[$name]))
1592  		$newvalue = $total[$name];
1593  	else
1594  		$newvalue = '';
1595  
1596  	list($showvalue, $class) = fmt('total', $name, $newvalue, $when, null);
1597  	echo "<td$class";
1598  	if ($rigtotals === true)
1599  		echo ' align=right';
1600  	echo ">$showvalue</td>";
1601   }
1602  }
1603  #
1604  function details($cmd, $list, $rig)
1605  {
1606   global $dfmt, $poolcmd, $readonly, $showndate;
1607   global $rownum, $rigtotals, $forcerigtotals, $singlerigsum;
1608  
1609   $when = 0;
1610  
1611   $stas = array('S' => 'Success', 'W' => 'Warning', 'I' => 'Informational', 'E' => 'Error', 'F' => 'Fatal');
1612  
1613   newtable();
1614  
1615   if ($showndate === false)
1616   {
1617  	showdatetime();
1618  
1619  	endtable();
1620  	newtable();
1621  
1622  	$showndate = true;
1623   }
1624  
1625   if (isset($list['STATUS']))
1626   {
1627  	newrow();
1628  	echo '<td>Computer: '.$list['STATUS']['Description'].'</td>';
1629  	if (isset($list['STATUS']['When']))
1630  	{
1631  		echo '<td>When: '.date($dfmt, $list['STATUS']['When']).'</td>';
1632  		$when = $list['STATUS']['When'];
1633  	}
1634  	$sta = $list['STATUS']['STATUS'];
1635  	echo '<td>Status: '.$stas[$sta].'</td>';
1636  	echo '<td>Message: '.$list['STATUS']['Msg'].'</td>';
1637  	endrow();
1638   }
1639  
1640   if ($rigtotals === true && isset($singlerigsum[$cmd]))
1641  	$dototal = $singlerigsum[$cmd];
1642   else
1643  	$dototal = array();
1644  
1645   $total = array();
1646  
1647   $section = '';
1648   $oldvalues = null;
1649   foreach ($list as $item => $values)
1650   {
1651  	if ($item == 'STATUS')
1652  		continue;
1653  
1654  	$sectionname = preg_replace('/\d/', '', $item);
1655  
1656  	// Handle 'devs' possibly containing >1 table
1657  	if ($sectionname != $section)
1658  	{
1659  		if ($oldvalues != null && count($total) > 0
1660  		&&  ($rownum > 2 || $forcerigtotals === true))
1661  			showtotal($total, $when, $oldvalues);
1662  
1663  		endtable();
1664  		newtable();
1665  		showhead($cmd, $values);
1666  		$section = $sectionname;
1667  	}
1668  
1669  	newrow();
1670  
1671  	foreach ($values as $name => $value)
1672  	{
1673  		list($showvalue, $class) = fmt($section, $name, $value, $when, $values);
1674  		echo "<td$class";
1675  		if ($rigtotals === true)
1676  			echo ' align=right';
1677  		echo ">$showvalue</td>";
1678  
1679  		if (isset($dototal[$name])
1680  		||  (isset($dototal['*']) and substr($name, 0, 1) == '*'))
1681  		{
1682  			if (isset($total[$name]))
1683  				$total[$name] += $value;
1684  			else
1685  				$total[$name] = $value;
1686  		}
1687  	}
1688  
1689  	if ($cmd == 'pools' && $readonly === false)
1690  	{
1691  		reset($values);
1692  		$pool = current($values);
1693  		foreach ($poolcmd as $name => $pcmd)
1694  		{
1695  			list($ignore, $class) = fmt('BUTTON', 'Pool', '', $when, $values);
1696  			echo "<td$class>";
1697  			if ($pool === false)
1698  				echo '&nbsp;';
1699  			else
1700  			{
1701  				echo "<input type=button value='Pool $pool'";
1702  				echo " onclick='prc(\"$pcmd|$pool&rig=$rig\",\"$name Pool $pool\")'>";
1703  			}
1704  			echo '</td>';
1705  		}
1706  	}
1707  	endrow();
1708  
1709  	$oldvalues = $values;
1710   }
1711  
1712   if ($oldvalues != null && count($total) > 0
1713   &&  ($rownum > 2 || $forcerigtotals === true))
1714  	showtotal($total, $when, $oldvalues);
1715  
1716   endtable();
1717  }
1718  #
1719  global $devs;
1720  $devs = null;
1721  #
1722  function showpoolinputs($rig, $ans)
1723  {
1724   global $readonly, $poolinputs;
1725  
1726   if ($readonly === true || $poolinputs === false)
1727  	return;
1728  
1729   newtable();
1730   newrow();
1731  
1732   $inps = array('Pool URL' => array('purl', 20),
1733  		'Worker Name' => array('pwork', 10),
1734  		'Worker Password' => array('ppass', 10));
1735   $b = '&nbsp;';
1736  
1737   echo "<td align=right class=h> Add a pool: </td><td>";
1738  
1739   foreach ($inps as $text => $name)
1740  	echo "$text: <input name='".$name[0]."' id='".$name[0]."' value='' type=text size=".$name[1]."> ";
1741  
1742   echo "</td><td align=middle><input type=button value='Add' onclick='pla($rig)'></td>";
1743  
1744   endrow();
1745  
1746   if (count($ans) > 1)
1747   {
1748  	newrow();
1749  
1750  	echo '<td align=right class=h> Set pool priorities: </td>';
1751  	echo "<td> Comma list of pool numbers: <input type=text name=prio id=prio size=20>";
1752  	echo "</td><td align=middle><input type=button value='Set' onclick='psp($rig)'></td>";
1753  
1754  	endrow();
1755   }
1756   endtable();
1757  }
1758  #
1759  function process($cmds, $rig)
1760  {
1761   global $error, $devs;
1762   global $warnfont, $warnoff;
1763  
1764   $count = count($cmds);
1765   foreach ($cmds as $cmd => $des)
1766   {
1767  	$process = api($rig, $cmd);
1768  
1769  	if ($error != null)
1770  	{
1771  		otherrow("<td colspan=100>Error getting $des: $warnfont$error$warnoff</td>");
1772  		break;
1773  	}
1774  	else
1775  	{
1776  		details($cmd, $process, $rig);
1777  
1778  		if ($cmd == 'devs')
1779  			$devs = $process;
1780  
1781  		if ($cmd == 'pools')
1782  			showpoolinputs($rig, $process);
1783  
1784  		# Not after the last one
1785  		if (--$count > 0)
1786  			otherrow('<td><br><br></td>');
1787  	}
1788   }
1789  }
1790  #
1791  function rigname($rig, $rigname)
1792  {
1793   global $rigs, $rignames, $rigips;
1794  
1795   if (isset($rigs[$rig]))
1796   {
1797  	$parts = explode(':', $rigs[$rig], 3);
1798  	if (count($parts) == 3)
1799  		$rigname = $parts[2];
1800  	else
1801  		if ($rignames !== false)
1802  		{
1803  			switch ($rignames)
1804  			{
1805  			case 'ip':
1806  				if (isset($parts[0]) && isset($rigips[$parts[0]]))
1807  				{
1808  					$ip = explode('.', $rigips[$parts[0]]);
1809  					if (count($ip) == 4)
1810  						$rigname = intval($ip[3]);
1811  				}
1812  				break;
1813  			case 'ipx':
1814  				if (isset($parts[0]) && isset($rigips[$parts[0]]))
1815  				{
1816  					$ip = explode('.', $rigips[$parts[0]]);
1817  					if (count($ip) == 4)
1818  						$rigname = intval($ip[3], 16);
1819  				}
1820  				break;
1821  			}
1822  		}
1823   }
1824  
1825   return $rigname;
1826  }
1827  #
1828  function riginput($rig, $rigname, $usebuttons)
1829  {
1830   $rigname = rigname($rig, $rigname);
1831  
1832   if ($usebuttons === true)
1833  	return "<input type=button value='$rigname' onclick='pr(\"&rig=$rig\",null)'>";
1834   else
1835  	return "<a href='".php_pr("&rig=$rig")."'>$rigname</a>";
1836  }
1837  #
1838  function rigbutton($rig, $rigname, $when, $row, $usebuttons)
1839  {
1840   list($value, $class) = fmt('BUTTON', 'Rig', '', $when, $row);
1841  
1842   if ($rig === '')
1843  	$ri = '&nbsp;';
1844   else
1845  	$ri = riginput($rig, $rigname, $usebuttons);
1846  
1847   return "<td align=middle$class>$ri</td>";
1848  }
1849  #
1850  function showrigs($anss, $headname, $rigname)
1851  {
1852   global $rigbuttons;
1853  
1854   $dthead = array($headname => 1, 'STATUS' => 1, 'Description' => 1, 'When' => 1, 'API' => 1, 'CGMiner' => 1);
1855   showhead('', $dthead);
1856  
1857   foreach ($anss as $rig => $ans)
1858   {
1859  	if ($ans == null)
1860  		continue;
1861  
1862  	newrow();
1863  
1864  	$when = 0;
1865  	if (isset($ans['STATUS']['When']))
1866  		$when = $ans['STATUS']['When'];
1867  
1868  	foreach ($ans as $item => $row)
1869  	{
1870  		if ($item != 'STATUS' && $item != 'VERSION')
1871  			continue;
1872  
1873  		foreach ($dthead as $name => $x)
1874  		{
1875  			if ($item == 'STATUS' && $name == $headname)
1876  				echo rigbutton($rig, $rigname.$rig, $when, null, $rigbuttons);
1877  			else
1878  			{
1879  				if (isset($row[$name]))
1880  				{
1881  					list($showvalue, $class) = fmt('STATUS', $name, $row[$name], $when, null);
1882  					echo "<td$class align=right>$showvalue</td>";
1883  				}
1884  			}
1885  		}
1886  	}
1887  	endrow();
1888   }
1889  }
1890  #
1891  function refreshbuttons()
1892  {
1893   global $ignorerefresh, $changerefresh, $autorefresh;
1894  
1895   if ($ignorerefresh == false && $changerefresh == true)
1896   {
1897  	echo '&nbsp;&nbsp;&nbsp;&nbsp;';
1898  	echo "<input type=button value='Auto Refresh:' onclick='prr(true)'>";
1899  	echo "<input type=text name='refval' id='refval' size=2 value='$autorefresh'>";
1900  	echo "<input type=button value='Off' onclick='prr(false)'>";
1901   }
1902  }
1903  #
1904  function pagebuttons($rig, $pg)
1905  {
1906   global $readonly, $rigs, $rigbuttons, $userlist, $ses;
1907   global $allowcustompages, $customsummarypages;
1908  
1909   if ($rig === null)
1910   {
1911  	$prev = null;
1912  	$next = null;
1913  
1914  	if ($pg === null)
1915  		$refresh = '';
1916  	else
1917  		$refresh = "&pg=$pg";
1918   }
1919   else
1920   {
1921  	switch (count($rigs))
1922  	{
1923  	case 0:
1924  	case 1:
1925  		$prev = null;
1926  		$next = null;
1927  		break;
1928  	case 2:
1929  		$prev = null;
1930  		$next = ($rig + 1) % count($rigs);
1931  		break;
1932  	default:
1933  		$prev = ($rig - 1) % count($rigs);
1934  		$next = ($rig + 1) % count($rigs);
1935  		break;
1936  	}
1937  
1938  	$refresh = "&rig=$rig";
1939   }
1940  
1941   echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>';
1942   if ($userlist === null || isset($_SESSION[$ses]))
1943   {
1944  	if ($prev !== null)
1945  		echo riginput($prev, 'Prev', true).'&nbsp;';
1946  
1947  	echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;";
1948  
1949  	if ($next !== null)
1950  		echo riginput($next, 'Next', true).'&nbsp;';
1951  	echo '&nbsp;';
1952  	if (count($rigs) > 1 and getcsp('Summary', true) !== false)
1953  		echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;";
1954   }
1955  
1956   if ($allowcustompages === true)
1957   {
1958  	if ($userlist === null || isset($_SESSION[$ses]))
1959  		$list = $customsummarypages;
1960  	else
1961  	{
1962  		if ($userlist !== null && isset($userlist['def']))
1963  			$list = array_flip($userlist['def']);
1964  		else
1965  			$list = array();
1966  	}
1967  
1968  	foreach ($list as $pagename => $data)
1969  		if (getcsp($pagename) !== false)
1970  			echo "<input type=button value='$pagename' onclick='pr(\"&pg=$pagename\",null)'>&nbsp;";
1971   }
1972  
1973   echo '</td><td width=100%>&nbsp;</td><td nowrap>';
1974   if ($rig !== null && $readonly === false)
1975   {
1976  	$rg = '';
1977  	if (count($rigs) > 1)
1978  		$rg = " Rig $rig";
1979  	echo "<input type=button value='Restart' onclick='prc(\"restart&rig=$rig\",\"Restart CGMiner$rg\")'>";
1980  	echo "&nbsp;<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"Quit CGMiner$rg\")'>";
1981   }
1982   refreshbuttons();
1983   if (isset($_SESSION[$ses]))
1984  	echo "&nbsp;<input type=button value='Logout' onclick='pr(\"&logout=1\",null)'>";
1985   else
1986  	if ($userlist !== null)
1987  		echo "&nbsp;<input type=button value='Login' onclick='pr(\"&login=1\",null)'>";
1988  
1989   echo "</td></tr></table></td></tr>";
1990  }
1991  #
1992  function doOne($rig, $preprocess)
1993  {
1994   global $haderror, $readonly, $notify, $rigs;
1995   global $placebuttons;
1996  
1997   if ($placebuttons == 'top' || $placebuttons == 'both')
1998  	pagebuttons($rig, null);
1999  
2000   if ($preprocess != null)
2001  	process(array($preprocess => $preprocess), $rig);
2002  
2003   $cmds = array(	'devs'    => 'device list',
2004  		'summary' => 'summary information',
2005  		'pools'   => 'pool list');
2006  
2007   if ($notify)
2008  	$cmds['notify'] = 'device status';
2009  
2010   $cmds['config'] = 'cgminer config';
2011  
2012   process($cmds, $rig);
2013  
2014   if ($placebuttons == 'bot' || $placebuttons == 'both')
2015  	pagebuttons($rig, null);
2016  }
2017  #
2018  global $sectionmap;
2019  # map sections to their api command
2020  # DEVS is a special case that will match PGA or ASC
2021  # so you can have a single table with both in it
2022  # DATE is hard coded so not in here
2023  $sectionmap = array(
2024  	'RIGS' => 'version',
2025  	'SUMMARY' => 'summary',
2026  	'POOL' => 'pools',
2027  	'DEVS' => 'devs',
2028  	'EDEVS' => 'edevs',
2029  	'PGA' => 'devs',	// You would normally use DEVS
2030  	'ASC' => 'devs',	// You would normally use DEVS
2031  	'NOTIFY' => 'notify',
2032  	'DEVDETAILS' => 'devdetails',
2033  	'STATS' => 'stats',
2034  	'ESTATS' => 'estats',
2035  	'CONFIG' => 'config',
2036  	'COIN' => 'coin',
2037  	'USBSTATS' => 'usbstats');
2038  #
2039  function joinfields($section1, $section2, $join, $results)
2040  {
2041   global $sectionmap;
2042  
2043   $name1 = $sectionmap[$section1];
2044   $name2 = $sectionmap[$section2];
2045   $newres = array();
2046  
2047   // foreach rig in section1
2048   foreach ($results[$name1] as $rig => $result)
2049   {
2050  	$status = null;
2051  
2052  	// foreach answer section in the rig api call
2053  	foreach ($result as $name1b => $fields1b)
2054  	{
2055  		if ($name1b == 'STATUS')
2056  		{
2057  			// remember the STATUS from section1
2058  			$status = $result[$name1b];
2059  			continue;
2060  		}
2061  
2062  		// foreach answer section in the rig api call (for the other api command)
2063  		foreach ($results[$name2][$rig] as $name2b => $fields2b)
2064  		{
2065  			if ($name2b == 'STATUS')
2066  				continue;
2067  
2068  			// If match the same field values of fields in $join
2069  			$match = true;
2070  			foreach ($join as $field)
2071  				if ($fields1b[$field] != $fields2b[$field])
2072  				{
2073  					$match = false;
2074  					break;
2075  				}
2076  
2077  			if ($match === true)
2078  			{
2079  				if ($status != null)
2080  				{
2081  					$newres[$rig]['STATUS'] = $status;
2082  					$status = null;
2083  				}
2084  
2085  				$subsection = $section1.'+'.$section2;
2086  				$subsection .= preg_replace('/[^0-9]/', '', $name1b.$name2b);
2087  
2088  				foreach ($fields1b as $nam => $val)
2089  					$newres[$rig][$subsection]["$section1.$nam"] = $val;
2090  				foreach ($fields2b as $nam => $val)
2091  					$newres[$rig][$subsection]["$section2.$nam"] = $val;
2092  			}
2093  		}
2094  	}
2095   }
2096   return $newres;
2097  }
2098  #
2099  function joinlr($section1, $section2, $join, $results)
2100  {
2101   global $sectionmap;
2102  
2103   $name1 = $sectionmap[$section1];
2104   $name2 = $sectionmap[$section2];
2105   $newres = array();
2106  
2107   // foreach rig in section1
2108   foreach ($results[$name1] as $rig => $result)
2109   {
2110  	$status = null;
2111  
2112  	// foreach answer section in the rig api call
2113  	foreach ($result as $name1b => $fields1b)
2114  	{
2115  		if ($name1b == 'STATUS')
2116  		{
2117  			// remember the STATUS from section1
2118  			$status = $result[$name1b];
2119  			continue;
2120  		}
2121  
2122  		// Build L string to be matched
2123  		// : means a string constant otherwise it's a field name
2124  		$Lval = '';
2125  		foreach ($join['L'] as $field)
2126  		{
2127  			if (substr($field, 0, 1) == ':')
2128  				$Lval .= substr($field, 1);
2129  			else
2130  				$Lval .= $fields1b[$field];
2131  		}
2132  
2133  		// foreach answer section in the rig api call (for the other api command)
2134  		foreach ($results[$name2][$rig] as $name2b => $fields2b)
2135  		{
2136  			if ($name2b == 'STATUS')
2137  				continue;
2138  
2139  			// Build R string and compare
2140  			// : means a string constant otherwise it's a field name
2141  			$Rval = '';
2142  			foreach ($join['R'] as $field)
2143  			{
2144  				if (substr($field, 0, 1) == ':')
2145  					$Rval .= substr($field, 1);
2146  				else
2147  					$Rval .= $fields2b[$field];
2148  			}
2149  
2150  			if ($Lval === $Rval)
2151  			{
2152  				if ($status != null)
2153  				{
2154  					$newres[$rig]['STATUS'] = $status;
2155  					$status = null;
2156  				}
2157  
2158  				$subsection = $section1.'+'.$section2;
2159  				$subsection .= preg_replace('/[^0-9]/', '', $name1b.$name2b);
2160  
2161  				foreach ($fields1b as $nam => $val)
2162  					$newres[$rig][$subsection]["$section1.$nam"] = $val;
2163  				foreach ($fields2b as $nam => $val)
2164  					$newres[$rig][$subsection]["$section2.$nam"] = $val;
2165  			}
2166  		}
2167  	}
2168   }
2169   return $newres;
2170  }
2171  #
2172  function joinall($section1, $section2, $results)
2173  {
2174   global $sectionmap;
2175  
2176   $name1 = $sectionmap[$section1];
2177   $name2 = $sectionmap[$section2];
2178   $newres = array();
2179  
2180   // foreach rig in section1
2181   foreach ($results[$name1] as $rig => $result)
2182   {
2183  	// foreach answer section in the rig api call
2184  	foreach ($result as $name1b => $fields1b)
2185  	{
2186  		if ($name1b == 'STATUS')
2187  		{
2188  			// copy the STATUS from section1
2189  			$newres[$rig][$name1b] = $result[$name1b];
2190  			continue;
2191  		}
2192  
2193  		// foreach answer section in the rig api call (for the other api command)
2194  		foreach ($results[$name2][$rig] as $name2b => $fields2b)
2195  		{
2196  			if ($name2b == 'STATUS')
2197  				continue;
2198  
2199  			$subsection = $section1.'+'.$section2;
2200  			$subsection .= preg_replace('/[^0-9]/', '', $name1b.$name2b);
2201  
2202  			foreach ($fields1b as $nam => $val)
2203  				$newres[$rig][$subsection]["$section1.$nam"] = $val;
2204  			foreach ($fields2b as $nam => $val)
2205  				$newres[$rig][$subsection]["$section2.$nam"] = $val;
2206  		}
2207  	}
2208   }
2209   return $newres;
2210  }
2211  #
2212  function joinsections($sections, $results, $errors)
2213  {
2214   global $sectionmap;
2215  
2216   foreach ($sections as $section => $fields)
2217  	if ($section != 'DATE' && !isset($sectionmap[$section]))
2218  	{
2219  		$both = explode('+', $section, 2);
2220  		if (count($both) > 1)
2221  		{
2222  			switch($both[0])
2223  			{
2224  			case 'SUMMARY':
2225  				switch($both[1])
2226  				{
2227  				case 'POOL':
2228  				case 'DEVS':
2229  				case 'EDEVS':
2230  				case 'CONFIG':
2231  				case 'COIN':
2232  					$sectionmap[$section] = $section;
2233  					$results[$section] = joinall($both[0], $both[1], $results);
2234  					break;
2235  				default:
2236  					$errors[] = "Error: Invalid section '$section'";
2237  					break;
2238  				}
2239  				break;
2240  			case 'DEVS':
2241  			case 'EDEVS':
2242  				switch($both[1])
2243  				{
2244  				case 'NOTIFY':
2245  				case 'DEVDETAILS':
2246  				case 'USBSTATS':
2247  					$join = array('Name', 'ID');
2248  					$sectionmap[$section] = $section;
2249  					$results[$section] = joinfields($both[0], $both[1], $join, $results);
2250  					break;
2251  				case 'STATS':
2252  				case 'ESTATS':
2253  					$join = array('L' => array('Name','ID'), 'R' => array('ID'));
2254  					$sectionmap[$section] = $section;
2255  					$results[$section] = joinlr($both[0], $both[1], $join, $results);
2256  					break;
2257  				default:
2258  					$errors[] = "Error: Invalid section '$section'";
2259  					break;
2260  				}
2261  				break;
2262  			case 'POOL':
2263  				switch($both[1])
2264  				{
2265  				case 'STATS':
2266  					$join = array('L' => array(':POOL','POOL'), 'R' => array('ID'));
2267  					$sectionmap[$section] = $section;
2268  					$results[$section] = joinlr($both[0], $both[1], $join, $results);
2269  					break;
2270  				default:
2271  					$errors[] = "Error: Invalid section '$section'";
2272  					break;
2273  				}
2274  				break;
2275  			default:
2276  				$errors[] = "Error: Invalid section '$section'";
2277  				break;
2278  			}
2279  		}
2280  		else
2281  			$errors[] = "Error: Invalid section '$section'";
2282  	}
2283  
2284   return array($results, $errors);
2285  }
2286  #
2287  function secmatch($section, $field)
2288  {
2289   if ($section == $field)
2290  	return true;
2291  
2292   if (($section == 'DEVS' || $section == 'EDEVS')
2293   &&  ($field == 'PGA' || $field == 'ASC'))
2294  	return true;
2295  
2296   return false;
2297  }
2298  #
2299  function customset($showfields, $sum, $section, $rig, $isbutton, $result, $total, $cf = NULL)
2300  {
2301   global $rigbuttons;
2302  
2303   $rn = 0;
2304   foreach ($result as $sec => $row)
2305   {
2306  	$secname = preg_replace('/\d/', '', $sec);
2307  
2308  	if ($sec != 'total')
2309  		if (!secmatch($section, $secname))
2310  			continue;
2311  
2312  	newrow();
2313  
2314  	$when = 0;
2315  	if (isset($result['STATUS']['When']))
2316  		$when = $result['STATUS']['When'];
2317  
2318  
2319  	if ($isbutton)
2320  		echo rigbutton($rig, $rig, $when, $row, $rigbuttons);
2321  	else
2322  	{
2323  		list($ignore, $class) = fmt('total', '', '', $when, $row, $cf);
2324  		echo "<td align=middle$class>$rig</td>";
2325  	}
2326  
2327  	foreach ($showfields as $name => $one)
2328  	{
2329  		if ($name === '#' and $sec != 'total')
2330  		{
2331  			$rn++;
2332  			$value = $rn;
2333  			if (isset($total[$name]))
2334  				$total[$name]++;
2335  			else
2336  				$total[$name] = 1;
2337  		}
2338  		elseif (isset($row[$name]))
2339  		{
2340  			$value = $row[$name];
2341  
2342  			if (isset($sum[$section][$name]))
2343  			{
2344  				if (isset($total[$name]))
2345  					$total[$name] += $value;
2346  				else
2347  					$total[$name] = $value;
2348  			}
2349  		}
2350  		else
2351  		{
2352  			if ($sec == 'total' && isset($total[$name]))
2353  				$value = $total[$name];
2354  			else
2355  				$value = null;
2356  		}
2357  
2358  		if (strpos($secname, '+') === false)
2359  			list($showvalue, $class) = fmt($secname, $name, $value, $when, $row, $cf);
2360  		else
2361  		{
2362  			if ($name != '#')
2363  				$parts = explode('.', $name, 2);
2364  			else
2365  				$parts[0] = $parts[1] = '#';
2366  			list($showvalue, $class) = fmt($parts[0], $parts[1], $value, $when, $row, $cf);
2367  		}
2368  
2369  		echo "<td$class align=right>$showvalue</td>";
2370  	}
2371  	endrow();
2372   }
2373   return $total;
2374  }
2375  #
2376  function docalc($func, $data)
2377  {
2378   switch ($func)
2379   {
2380   case 'sum':
2381  	$tot = 0;
2382  	foreach ($data as $val)
2383  		$tot += $val;
2384  	return $tot;
2385   case 'avg':
2386  	$tot = 0;
2387  	foreach ($data as $val)
2388  		$tot += $val;
2389  	return ($tot / count($data));
2390   case 'min':
2391  	$ans = null;
2392  	foreach ($data as $val)
2393  		if ($ans === null)
2394  			$ans = $val;
2395  		else
2396  			if ($val < $ans)
2397  				$ans = $val;
2398  	return $ans;
2399   case 'max':
2400  	$ans = null;
2401  	foreach ($data as $val)
2402  		if ($ans === null)
2403  			$ans = $val;
2404  		else
2405  			if ($val > $ans)
2406  				$ans = $val;
2407  	return $ans;
2408   case 'lo':
2409  	$ans = null;
2410  	foreach ($data as $val)
2411  		if ($ans === null)
2412  			$ans = $val;
2413  		else
2414  			if (strcasecmp($val, $ans) < 0)
2415  				$ans = $val;
2416  	return $ans;
2417   case 'hi':
2418  	$ans = null;
2419  	foreach ($data as $val)
2420  		if ($ans === null)
2421  			$ans = $val;
2422  		else
2423  			if (strcasecmp($val, $ans) > 0)
2424  				$ans = $val;
2425  	return $ans;
2426   case 'count':
2427  	return count($data);
2428   case 'any':
2429   default:
2430  	return $data[0];
2431   }
2432  }
2433  #
2434  function docompare($row, $test)
2435  {
2436   // invalid $test data means true
2437   if (count($test) < 2)
2438  	return true;
2439  
2440   if (isset($row[$test[0]]))
2441  	$val = $row[$test[0]];
2442   else
2443  	$val = null;
2444  
2445   if ($test[1] == 'set')
2446  	return ($val !== null);
2447  
2448   if ($val === null || count($test) < 3)
2449  	return true;
2450  
2451   switch($test[1])
2452   {
2453   case '=':
2454  	return ($val == $test[2]);
2455   case '<':
2456  	return ($val < $test[2]);
2457   case '<=':
2458  	return ($val <= $test[2]);
2459   case '>':
2460  	return ($val > $test[2]);
2461   case '>=':
2462  	return ($val >= $test[2]);
2463   case 'eq':
2464  	return (strcasecmp($val, $test[2]) == 0);
2465   case 'lt':
2466  	return (strcasecmp($val, $test[2]) < 0);
2467   case 'le':
2468  	return (strcasecmp($val, $test[2]) <= 0);
2469   case 'gt':
2470  	return (strcasecmp($val, $test[2]) > 0);
2471   case 'ge':
2472  	return (strcasecmp($val, $test[2]) >= 0);
2473   default:
2474  	return true;
2475   }
2476  }
2477  #
2478  function processcompare($which, $ext, $section, $res)
2479  {
2480   if (isset($ext[$section][$which]))
2481   {
2482  	$proc = $ext[$section][$which];
2483  	if ($proc !== null)
2484  	{
2485  		$res2 = array();
2486  		foreach ($res as $rig => $result)
2487  			foreach ($result as $sec => $row)
2488  			{
2489  				$secname = preg_replace('/\d/', '', $sec);
2490  				if (!secmatch($section, $secname))
2491  					$res2[$rig][$sec] = $row;
2492  				else
2493  				{
2494  					$keep = true;
2495  					foreach ($proc as $test)
2496  						if (!docompare($row, $test))
2497  						{
2498  							$keep = false;
2499  							break;
2500  						}
2501  					if ($keep)
2502  						$res2[$rig][$sec] = $row;
2503  				}
2504  			}
2505  
2506  		$res = $res2;
2507  	}
2508   }
2509   return $res;
2510  }
2511  #
2512  function ss($a, $b)
2513  {
2514   $la = strlen($a);
2515   $lb = strlen($b);
2516   if ($la != $lb)
2517  	return $lb - $la;
2518   return strcmp($a, $b);
2519  }
2520  #
2521  # If you are developing a customsummarypage that uses BGEN or GEN,
2522  # you may want to remove the '@' in front of '@eval()' to help with debugging
2523  # The '@' removes php comments from the web log about missing fields
2524  # Since there are many forks of cgminer that break the API or do not
2525  # keep their fork up to date with current cgminer, the addition of
2526  # '@' solves the problem of generating unnecessary and excessive web logs
2527  # about the eval()
2528  function genfld($row, $calc)
2529  {
2530   uksort($row, "ss");
2531  
2532   foreach ($row as $name => $value)
2533  	if (strstr($calc, $name) !== FALSE)
2534  		$calc = str_replace($name, $value, $calc);
2535  
2536   @eval("\$val = $calc;");
2537  
2538   if (!isset($val))
2539  	return '';
2540   else
2541  	return $val;
2542  }
2543  #
2544  function dogen($ext, $wg, $gname, $section, &$res, &$fields)
2545  {
2546   $gen = $ext[$section][$wg];
2547  
2548   foreach ($gen as $fld => $calc)
2549  	$fields[] = "$gname.$fld";
2550  
2551   foreach ($res as $rig => $result)
2552  	foreach ($result as $sec => $row)
2553  	{
2554  		$secname = preg_replace('/\d/', '', $sec);
2555  		if (secmatch($section, $secname))
2556  			foreach ($gen as $fld => $calc)
2557  			{
2558  				$name = "$gname.$fld";
2559  
2560  				$val = genfld($row, $calc);
2561  
2562  				$res[$rig][$sec][$name] = $val;
2563  			}
2564  	}
2565  }
2566  #
2567  function processext($ext, $section, $res, &$fields)
2568  {
2569   global $allowgen;
2570  
2571   $res = processcompare('where', $ext, $section, $res);
2572  
2573   // Generated fields (functions of other fields before grouping)
2574   if ($allowgen === true && isset($ext[$section]['bgen']))
2575  	dogen($ext, 'bgen', 'BGEN', $section, $res, $fields);
2576  
2577   if (isset($ext[$section]['group']))
2578   {
2579  	$grp = $ext[$section]['group'];
2580  	$calc = $ext[$section]['calc'];
2581  	if ($grp !== null)
2582  	{
2583  		$interim = array();
2584  		$res2 = array();
2585  		$cou = 0;
2586  		foreach ($res as $rig => $result)
2587  			foreach ($result as $sec => $row)
2588  			{
2589  				$secname = preg_replace('/\d/', '', $sec);
2590  				if (!secmatch($section, $secname))
2591  				{
2592  					// STATUS may be problematic ...
2593  					if (!isset($res2[$sec]))
2594  						$res2[$sec] = $row;
2595  				}
2596  				else
2597  				{
2598  					$grpkey = '';
2599  					$newrow = array();
2600  					foreach ($grp as $field)
2601  					{
2602  						if (isset($row[$field]))
2603  						{
2604  							$grpkey .= $row[$field].'.';
2605  							$newrow[$field] = $row[$field];
2606  						}
2607  						else
2608  							$grpkey .= '.';
2609  					}
2610  
2611  					if (!isset($interim[$grpkey]))
2612  					{
2613  						$interim[$grpkey]['grp'] = $newrow;
2614  						$interim[$grpkey]['sec'] = $secname.$cou;
2615  						$cou++;
2616  					}
2617  
2618  					if ($calc !== null)
2619  						foreach ($calc as $field => $func)
2620  						{
2621  							if (isset($row[$field]))
2622  							{
2623  								if (!isset($interim[$grpkey]['cal'][$field]))
2624  									$interim[$grpkey]['cal'][$field] = array();
2625  								$interim[$grpkey]['cal'][$field][] = $row[$field];
2626  							}
2627  						}
2628  				}
2629  			}
2630  
2631  		// Build the rest of $res2 from $interim
2632  		foreach ($interim as $rowkey => $row)
2633  		{
2634  			$key = $row['sec'];
2635  			foreach ($row['grp'] as $field => $value)
2636  				$res2[$key][$field] = $value;
2637  			foreach ($row['cal'] as $field => $data)
2638  				$res2[$key][$field] = docalc($calc[$field], $data);
2639  		}
2640  
2641  		$res = array('' => $res2);
2642  	}
2643   }
2644  
2645   // Generated fields (functions of other fields after grouping)
2646   if ($allowgen === true && isset($ext[$section]['gen']))
2647  	dogen($ext, 'gen', 'GEN', $section, $res, $fields);
2648  
2649   return processcompare('having', $ext, $section, $res);
2650  }
2651  #
2652  function processcustompage($pagename, $sections, $sum, $ext, $namemap)
2653  {
2654   global $sectionmap;
2655   global $miner, $port;
2656   global $rigs, $error;
2657   global $warnfont, $warnoff;
2658   global $dfmt;
2659   global $readonly, $showndate;
2660  
2661   $cmds = array();
2662   $errors = array();
2663   foreach ($sections as $section => $fields)
2664   {
2665  	$all = explode('+', $section);
2666  	foreach ($all as $section)
2667  	{
2668  		if (isset($sectionmap[$section]))
2669  		{
2670  			$cmd = $sectionmap[$section];
2671  			if (!isset($cmds[$cmd]))
2672  				$cmds[$cmd] = 1;
2673  		}
2674  		else
2675  			if ($section != 'DATE')
2676  				$errors[] = "Error: unknown section '$section' in custom summary page '$pagename'";
2677  	}
2678   }
2679  
2680   $results = array();
2681   foreach ($rigs as $num => $rig)
2682   {
2683  	$parts = explode(':', $rig, 3);
2684  	if (count($parts) >= 1)
2685  	{
2686  		$miner = $parts[0];
2687  		if (count($parts) >= 2)
2688  			$port = $parts[1];
2689  		else
2690  			$port = '';
2691  
2692  		if (count($parts) > 2)
2693  			$name = $parts[2];
2694  		else
2695  			$name = $rig;
2696  
2697  		foreach ($cmds as $cmd => $one)
2698  		{
2699  			$process = api($name, $cmd);
2700  
2701  			if ($error != null)
2702  			{
2703  				$errors[] = "Error getting $cmd for $name $warnfont$error$warnoff";
2704  				break;
2705  			}
2706  			else
2707  				$results[$cmd][$num] = $process;
2708  		}
2709  	}
2710  	else
2711  		otherrow('<td class=bad>Bad "$rigs" array</td>');
2712   }
2713  
2714   // Show API errors at the top
2715   if (count($errors) > 0)
2716   {
2717  	foreach ($errors as $err)
2718  		otherrow("<td colspan=100>$err</td>");
2719  	$errors = array();
2720   }
2721  
2722   $shownsomething = false;
2723   if (count($results) > 0)
2724   {
2725  	list($results, $errors) = joinsections($sections, $results, $errors);
2726  	$first = true;
2727  	foreach ($sections as $section => $fields)
2728  	{
2729  		if ($section === 'DATE')
2730  		{
2731  			if ($shownsomething)
2732  				otherrow('<td>&nbsp;</td>');
2733  
2734  			newtable();
2735  			showdatetime();
2736  			endtable();
2737  			// On top of the next table
2738  			$shownsomething = false;
2739  			continue;
2740  		}
2741  
2742  		if ($section === 'RIGS')
2743  		{
2744  			if ($shownsomething)
2745  				otherrow('<td>&nbsp;</td>');
2746  
2747  			newtable();
2748  			showrigs($results['version'], 'Rig', '');
2749  			endtable();
2750  			$shownsomething = true;
2751  			continue;
2752  		}
2753  
2754  		if (isset($results[$sectionmap[$section]]))
2755  		{
2756  			if (isset($ext[$section]['fmt']))
2757  				$cf = $ext[$section]['fmt'];
2758  			else
2759  				$cf = NULL;
2760  
2761  			$rigresults = processext($ext, $section, $results[$sectionmap[$section]], $fields);
2762  
2763  			$showfields = array();
2764  			$showhead = array();
2765  			foreach ($fields as $field)
2766  				foreach ($rigresults as $result)
2767  					foreach ($result as $sec => $row)
2768  					{
2769  						$secname = preg_replace('/\d/', '', $sec);
2770  						if (secmatch($section, $secname))
2771  						{
2772  							if ($field === '*')
2773  							{
2774  								foreach ($row as $f => $v)
2775  								{
2776  									$showfields[$f] = 1;
2777  									$map = $section.'.'.$f;
2778  									if (isset($namemap[$map]))
2779  										$showhead[$namemap[$map]] = 1;
2780  									else
2781  										$showhead[$f] = 1;
2782  								}
2783  							}
2784  							elseif ($field === '#')
2785  							{
2786  								$showfields[$field] = 1;
2787  								$showhead[$field] = 1;
2788  							}
2789  							elseif (isset($row[$field]))
2790  							{
2791  								$showfields[$field] = 1;
2792  								$map = $section.'.'.$field;
2793  								if (isset($namemap[$map]))
2794  									$showhead[$namemap[$map]] = 1;
2795  								else
2796  									$showhead[$field] = 1;
2797  							}
2798  						}
2799  					}
2800  
2801  			if (count($showfields) > 0)
2802  			{
2803  				if ($shownsomething)
2804  					otherrow('<td>&nbsp;</td>');
2805  
2806  				newtable();
2807  				if (count($rigresults) == 1 && isset($rigresults['']))
2808  					$ri = array('' => 1) + $showhead;
2809  				else
2810  					$ri = array('Rig' => 1) + $showhead;
2811  				showhead('', $ri, true);
2812  
2813  				$total = array();
2814  				$add = array('total' => array());
2815  
2816  				foreach ($rigresults as $num => $result)
2817  					$total = customset($showfields, $sum, $section, $num, true, $result, $total, $cf);
2818  
2819  				if (count($total) > 0)
2820  					customset($showfields, $sum, $section, '&Sigma;', false, $add, $total, $cf);
2821  
2822  				$first = false;
2823  
2824  				endtable();
2825  				$shownsomething = true;
2826  			}
2827  		}
2828  	}
2829   }
2830  
2831   if (count($errors) > 0)
2832   {
2833  	if (count($results) > 0)
2834  		otherrow('<td>&nbsp;</td>');
2835  
2836  	foreach ($errors as $err)
2837  		otherrow("<td colspan=100>$err</td>");
2838   }
2839  }
2840  #
2841  function showcustompage($pagename, $systempage = false)
2842  {
2843   global $customsummarypages;
2844   global $placebuttons;
2845  
2846   if ($placebuttons == 'top' || $placebuttons == 'both')
2847  	pagebuttons(null, $pagename);
2848  
2849   if ($systempage === false && !isset($customsummarypages[$pagename]))
2850   {
2851  	otherrow("<td colspan=100 class=bad>Unknown custom summary page '$pagename'</td>");
2852  	return;
2853   }
2854  
2855   $csp = getcsp($pagename, $systempage);
2856   if ($csp === false)
2857   {
2858  	otherrow("<td colspan=100 class=bad>Invalid custom summary page '$pagename'</td>");
2859  	return;
2860   }
2861  
2862   degen($csp);
2863  
2864   $page = $csp[0];
2865   $namemap = array();
2866   foreach ($page as $name => $fields)
2867   {
2868  	if ($fields === null)
2869  		$page[$name] = array();
2870  	else
2871  		foreach ($fields as $num => $field)
2872  		{
2873  			$pos = strpos($field, '=');
2874  			if ($pos !== false)
2875  			{
2876  				$names = explode('=', $field, 2);
2877  				if (strlen($names[1]) > 0)
2878  					$namemap[$name.'.'.$names[0]] = $names[1];
2879  				$page[$name][$num] = $names[0];
2880  			}
2881  		}
2882   }
2883  
2884   $ext = null;
2885   if (isset($csp[2]))
2886  	$ext = $csp[2];
2887  
2888   $sum = $csp[1];
2889   if ($sum === null)
2890  	$sum = array();
2891  
2892   // convert them to searchable via isset()
2893   foreach ($sum as $section => $fields)
2894   {
2895  	$newfields = array();
2896  	foreach ($fields as $field)
2897  		$newfields[$field] = 1;
2898  	$sum[$section] = $newfields;
2899   }
2900  
2901   if (count($page) <= 1)
2902   {
2903  	otherrow("<td colspan=100 class=bad>Invalid custom summary page '$pagename' no content </td>");
2904  	return;
2905   }
2906  
2907   processcustompage($pagename, $page, $sum, $ext, $namemap);
2908  
2909   if ($placebuttons == 'bot' || $placebuttons == 'both')
2910  	pagebuttons(null, $pagename);
2911  }
2912  #
2913  function onlylogin()
2914  {
2915   global $here;
2916  
2917   htmlhead('', false, null, null, true);
2918  
2919  ?>
2920  <tr height=15%><td>&nbsp;</td></tr>
2921  <tr><td>
2922   <center>
2923    <table width=384 height=368 cellpadding=0 cellspacing=0 border=0>
2924     <tr><td>
2925      <table width=100% height=100% border=0 align=center cellpadding=5 cellspacing=0>
2926       <tr><td><form action='<?php echo $here; ?>' method=post>
2927        <table width=200 border=0 align=center cellpadding=5 cellspacing=0>
2928         <tr><td height=120 colspan=2>&nbsp;</td></tr>
2929         <tr><td colspan=2 align=center valign=middle>
2930          <h2>LOGIN</h2></td></tr>
2931         <tr><td align=center valign=middle><div align=right>Username:</div></td>
2932          <td height=33 align=center valign=middle>
2933          <input type=text name=rut size=18></td></tr>
2934         <tr><td align=center valign=middle><div align=right>Password:</div></td>
2935          <td height=33 align=center valign=middle>
2936          <input type=password name=roh size=18></td></tr>
2937         <tr valign=top><td></td><td><input type=submit value=Login>
2938          </td></tr>
2939        </table></form></td></tr>
2940      </table></td></tr>
2941    </table></center>
2942  </td></tr>
2943  <?php
2944  }
2945  #
2946  function checklogin()
2947  {
2948   global $allowcustompages;
2949   global $readonly, $userlist, $ses;
2950  
2951   $out = trim(getparam('logout', true));
2952   if ($out !== null && $out !== '' && isset($_SESSION[$ses]))
2953  	unset($_SESSION[$ses]);
2954  
2955   $login = trim(getparam('login', true));
2956   if ($login !== null && $login !== '')
2957   {
2958  	if (isset($_SESSION[$ses]))
2959  		unset($_SESSION[$ses]);
2960  
2961  	onlylogin();
2962  	return 'login';
2963   }
2964  
2965   if ($userlist === null)
2966  	return false;
2967  
2968   $rut = trim(getparam('rut', true));
2969   $roh = trim(getparam('roh', true));
2970  
2971   if (($rut !== null && $rut !== '') || ($roh !== null && $roh !== ''))
2972   {
2973  	if (isset($_SESSION[$ses]))
2974  		unset($_SESSION[$ses]);
2975  
2976  	if ($rut !== null && $rut !== '' && $roh !== null && $roh !== '')
2977  	{
2978  		if (isset($userlist['sys']) && isset($userlist['sys'][$rut])
2979  		&&  ($userlist['sys'][$rut] === $roh))
2980  		{
2981  			$_SESSION[$ses] = true;
2982  			return false;
2983  		}
2984  
2985  		if (isset($userlist['usr']) && isset($userlist['usr'][$rut])
2986  		&&  ($userlist['usr'][$rut] === $roh))
2987  		{
2988  			$_SESSION[$ses] = false;
2989  			$readonly = true;
2990  			return false;
2991  		}
2992  	}
2993   }
2994  
2995   if (isset($_SESSION[$ses]))
2996   {
2997  	if ($_SESSION[$ses] == false)
2998  		$readonly = true;
2999  	return false;
3000   }
3001  
3002   if (isset($userlist['def']) && $allowcustompages === true)
3003   {
3004  	// Ensure at least one exists
3005  	foreach ($userlist['def'] as $pg)
3006  		if (getcsp($pg) !== false)
3007  			return true;
3008   }
3009  
3010   onlylogin();
3011   return 'login';
3012  }
3013  #
3014  function display()
3015  {
3016   global $miner, $port;
3017   global $mcast, $mcastexpect;
3018   global $readonly, $notify, $rigs;
3019   global $ignorerefresh, $autorefresh;
3020   global $allowcustompages;
3021   global $placebuttons;
3022   global $userlist, $ses;
3023  
3024   $pagesonly = checklogin();
3025  
3026   if ($pagesonly === 'login')
3027  	return;
3028  
3029   $mcerr = '';
3030  
3031   if ($rigs == null or count($rigs) == 0)
3032   {
3033  	if ($mcast === true)
3034  		$action = 'found';
3035  	else
3036  		$action = 'defined';
3037  
3038  	minhead();
3039  	otherrow("<td class=bad>No rigs $action</td>");
3040  	return;
3041   }
3042   else
3043   {
3044  	if ($mcast === true && count($rigs) < $mcastexpect)
3045  		$mcerr = othrow('<td class=bad>Found '.count($rigs)." rigs but expected at least $mcastexpect</td>");
3046   }
3047  
3048   if ($ignorerefresh == false)
3049   {
3050  	$ref = trim(getparam('ref', true));
3051  	if ($ref != null && $ref != '')
3052  		$autorefresh = intval($ref);
3053   }
3054  
3055   if ($pagesonly !== true)
3056   {
3057  	$rig = trim(getparam('rig', true));
3058  
3059  	$arg = trim(getparam('arg', true));
3060  	$preprocess = null;
3061  	if ($arg != null and $arg != '')
3062  	{
3063  		if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs))
3064  		{
3065  			$parts = explode(':', $rigs[$rig], 3);
3066  			if (count($parts) >= 1)
3067  			{
3068  				$miner = $parts[0];
3069  				if (count($parts) >= 2)
3070  					$port = $parts[1];
3071  				else
3072  					$port = '';
3073  
3074  				if ($readonly !== true)
3075  					$preprocess = $arg;
3076  			}
3077  		}
3078  	}
3079   }
3080  
3081   if ($allowcustompages === true)
3082   {
3083  	$pg = urlencode(trim(getparam('pg', true)));
3084  	if ($pagesonly === true)
3085  	{
3086  		if ($pg !== null && $pg !== '')
3087  		{
3088  			if ($userlist !== null && isset($userlist['def'])
3089  			&&  !in_array($pg, $userlist['def']))
3090  				$pg = null;
3091  		}
3092  		else
3093  		{
3094  			if ($userlist !== null && isset($userlist['def']))
3095  				foreach ($userlist['def'] as $pglook)
3096  					if (getcsp($pglook) !== false)
3097  					{
3098  						$pg = $pglook;
3099  						break;
3100  					}
3101  		}
3102  	}
3103  
3104  	if ($pg !== null && $pg !== '')
3105  	{
3106  		htmlhead($mcerr, false, null, $pg);
3107  		showcustompage($pg);
3108  		return;
3109  	}
3110   }
3111  
3112   if ($pagesonly === true)
3113   {
3114  	onlylogin();
3115  	return;
3116   }
3117  
3118   if (count($rigs) == 1)
3119   {
3120  	$parts = explode(':', $rigs[0], 3);
3121  	if (count($parts) >= 1)
3122  	{
3123  		$miner = $parts[0];
3124  		if (count($parts) >= 2)
3125  			$port = $parts[1];
3126  		else
3127  			$port = '';
3128  
3129  		htmlhead($mcerr, true, 0);
3130  		doOne(0, $preprocess);
3131  	}
3132  	else
3133  	{
3134  		minhead($mcerr);
3135  		otherrow('<td class=bad>Invalid "$rigs" array</td>');
3136  	}
3137  
3138  	return;
3139   }
3140  
3141   if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs))
3142   {
3143  	$parts = explode(':', $rigs[$rig], 3);
3144  	if (count($parts) >= 1)
3145  	{
3146  		$miner = $parts[0];
3147  		if (count($parts) >= 2)
3148  			$port = $parts[1];
3149  		else
3150  			$port = '';
3151  
3152  		htmlhead($mcerr, true, 0);
3153  		doOne($rig, $preprocess);
3154  	}
3155  	else
3156  	{
3157  		minhead($mcerr);
3158  		otherrow('<td class=bad>Invalid "$rigs" array</td>');
3159  	}
3160  
3161  	return;
3162   }
3163  
3164   htmlhead($mcerr, false, null);
3165  
3166   if ($preprocess != null)
3167  	process(array($preprocess => $preprocess), $rig);
3168  
3169   if (getcsp('Summary', true) !== false)
3170  	showcustompage('Summary', true);
3171  }
3172  #
3173  if ($mcast === true)
3174   getrigs();
3175  display();
3176  #
3177  ?>
3178  </table></td></tr></table>
3179  </body></html>