<?php
/*******************************************************************************
 *
 * LOVD DATABASE OPERATOR FILE
 *
 * Created     : 2006-05-01
 * Modified    : 2009-06-19
 * For LOVD    : 2.0-19
 *
 * Access      : Curators and up.
 * Purpose     : Check LOVD download site for updates of LOVD.
 *
 * Copyright   : 2004-2009 Leiden University Medical Center; http://www.LUMC.nl/
 * Programmer  : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 * Last edited : Ing. Ivo F.A.C. Fokkema <I.F.A.C.Fokkema@LUMC.nl>
 *
 *
 * This file is part of LOVD.
 *
 * LOVD is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * LOVD is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LOVD; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *************/

define('ROOT_PATH', './');
require ROOT_PATH . 'inc-init.php';

if (!isset($_GET['icon'])) {
    // Only authorized people...
    lovd_requireAuth(LEVEL_CURATOR);
}

// For the first time, or forced check.
// 2009-02-25; 2.0-16; Added "check now" option.
if ($_STAT['update_check'] == NULL || (isset($_GET['force_check']) && md5($_STAT['update_check']) == $_GET['force_check'])) {
    // Any date surely in the past.
    $_STAT['update_check'] = '1970-01-01';
}

// If the date of last update check was longer than one day ago, check again.
if ((time() - strtotime($_STAT['update_check'])) > (60*60*24)) {
    // If we're checking for updates, we want to see if we're sending statistics as well.
    $sURLVars = '?version=' . $_SETT['system']['version'];

    if ($_CONF['send_signature']) {
        $sURLVars .= '&signature=' . $_STAT['signature'];
    }

    // Software information.
    $sServer = PHP_OS . ' ' . $_SERVER['SERVER_SOFTWARE'];
    // 2008-02-28; 2.0-04; Remove excessive module information.
    if (preg_match('/^([^\(\)]+\(.+\))[^\(\)]+$/', $sServer, $aRegs)) {
        // Too much! Remove all after "(Platform)"!
        $sServer = $aRegs[1];
    }
    if (!substr_count($sServer, 'PHP')) {
        // PHP stuff hidden. Alright, then.
        $sServer .= ' PHP/' . PHP_VERSION;
    }
    $sServer = rawurlencode($sServer . ' MySQL/' . mysql_get_server_info());
    $sURLVars .= '&software=' . $sServer;
    $sGeneList = '';

    if ($_CONF['send_stats']) {
        // Collect stats...
        require ROOT_PATH . 'class/currdb.php';

        // Number of submitters.
        list($nSubs) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_SUBS . ' WHERE deleted = 0'));
        $sURLVars .= '&submitter_count=' . $nSubs;

        // Number of genes.
        $aGenes = lovd_getGeneList();
        $nGenes = count($aGenes);
        $sURLVars .= '&gene_count=' . $nGenes;

        // Patient count.
        list($nPatients) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_PATIENTS));
        $sURLVars .= '&patient_count=' . $nPatients;

        // Number of unique variants.
        $nUniqueVariants = 0;
        foreach ($aGenes as $sSymbol) {
            $_CURRDB = new CurrDB(true, $sSymbol);
            $sMutationCol = $_CURRDB->getMutationCol();

            // Number of unique variants.
            if (!$sMutationCol) {
                $n = 0;
            } else {
                list($n) = mysql_fetch_row(mysql_query('SELECT COUNT(DISTINCT `' . $sMutationCol . '`) FROM ' . TABLEPREFIX . '_' . $sSymbol . '_variants'));
            }
            $nUniqueVariants += $n;
            $sGeneList .= ($sGeneList? ',' : '') . $sSymbol;
        }
        $sURLVars .= '&uniquevariant_count=' . $nUniqueVariants;

        // Number of variants.
        // 2008-06-17; 2.0-08; $_CURRDB does not necessarily exists, if there is no gene this will return an error.
        if (isset($_CURRDB) && $_CURRDB->colExists('Patient/Times_Reported')) {
            list($nVariants) = mysql_fetch_row(mysql_query('SELECT SUM(p.`Patient/Times_Reported`) FROM ' . TABLE_PATIENTS . ' AS p LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v USING (patientid)'));
            settype($nVariants, 'int'); // Convert NULL to 0.
        } else {
            list($nVariants) = mysql_fetch_row(mysql_query('SELECT COUNT(*) FROM ' . TABLE_PAT2VAR));
        }
        $sURLVars .= '&variant_count=' . $nVariants;
    }

    if ($_CONF['send_listings']) {
        // Fetch install directory and gene listings.
        $sURLVars .= '&install_name=' . rawurlencode($_CONF['system_title']);

        // 2009-03-11; 2.0-17; Get the installation location from the database, if available.
        if (!empty($_CONF['location_url'])) {
            $sInstallDir = $_CONF['location_url'];
        } else {
            $sInstallDir = PROTOCOL . $_SERVER['HTTP_HOST'] . lovd_cleanDirName(dirname($_SERVER['PHP_SELF']) . '/' . ROOT_PATH);
        }
        $sURLVars .= '&install_dir=' . rawurlencode($sInstallDir);

        $sURLVars .= '&gene_listing=' . rawurlencode($sGeneList);

        // 2009-03-11; 2.0-17; Send setting for wiki indexing.
        list($bAllowIndex) = mysql_fetch_row(mysql_query('SELECT MAX(allow_index_wiki) FROM ' . TABLE_DBS));
        $sURLVars .= '&allow_index_wiki=' . (int) $bAllowIndex;
    }

    // Contact upstream.
    if (ini_get('allow_url_fopen')) {
        // Old default (and simple) method.
        $sUpdates = trim(@file_get_contents($_SETT['update_URL'] . $sURLVars));
    } else {
        // FIXME; Use lovd_php_file() in stead of the code below. NOTE: lovd_php_file() does not unset $aOutput[0]...
        // 2009-06-19; 2.0-19; implemented fsockopen() because file_get_contents could be blocked by disabling the fopen wrappers.
        $aURL = parse_url($_SETT['update_URL']);
        $f = @fsockopen($aURL['host'], 80);
        $sRequest = 'GET ' . $aURL['path'] . $sURLVars . ' HTTP/1.1' . "\r\n" .
                    'Host: ' . $aURL['host'] . "\r\n" .
                    'Connection: Close' . "\r\n\r\n";
        fputs($f, $sRequest);
        $aOutput = array();
        $bListen = false; // We want to start capturing the output AFTER the headers have ended.
        while (!feof($f)) {
            if ($bListen) {
                $aOutput[] = fgets($f, 4096);
            } else {
                $s = trim(fgets($f, 4096));
                if (!$s) {
                    $bListen = true;
                }
            }
        }
        fclose($f);
        unset($aOutput[0]); // Some weird hexadecimal code.

        $sUpdates = '';
        foreach ($aOutput as $sLine) {
            if (!trim($sLine)) {
                break;
            }
            $sUpdates .= $sLine;
        }
    }

    $sNow = date('Y-m-d H:i:s');
    if (preg_match('/^Package\s*:\s*LOVD\nVersion\s*:\s*' . $_SETT['system']['version'] . '(\nReleased\s*:\s*[0-9]{4}\-[0-9]{2}\-[0-9]{2})?$/', $sUpdates)) {
        // No update available.
        @mysql_query('UPDATE ' . TABLE_STATUS . ' SET update_check = "' . $sNow . '", update_version = "' . $_SETT['system']['version'] . '", update_level = 0, update_description = "", update_released = NULL');
        $_STAT['update_check'] = $sNow;
        $_STAT['update_version'] = $_SETT['system']['version'];
        $_STAT['update_released'] = '';
        $_STAT['update_level'] = 0;
        $_STAT['update_description'] = '';

    } elseif (preg_match('/^Package\s*:\s*LOVD\nVersion\s*:\s*([1-9]\.[0-9](\.[0-9])?(\-[0-9a-z-]{2,11})?)(\nReleased\s*:\s*[0-9]{4}\-[0-9]{2}\-[0-9]{2})?$/', $sUpdates, $aUpdates) && is_array($aUpdates)) {
        // Weird version conflict?
        lovd_writeLog('MySQL:Error', 'CheckUpdate', 'Version conflict while parsing upstream server output: current version (' . $_SETT['system']['version'] . ') > ' . $aUpdates[1]);
        @mysql_query('UPDATE ' . TABLE_STATUS . ' SET update_check = "' . $sNow . '", update_version = "Error", update_level = 0, update_description = "", update_released = NULL');
        $_STAT['update_check'] = $sNow;
        $_STAT['update_version'] = 'Error';
        $_STAT['update_released'] = '';
        $_STAT['update_level'] = 0;
        $_STAT['update_description'] = '';

    } elseif (preg_match('/^Package\s*:\s*LOVD\nVersion\s*:\s*([1-9]\.[0-9](\.[0-9])?\-([0-9a-z-]{2,11}))(\nReleased\s*:\s*([0-9]{4}\-[0-9]{2}\-[0-9]{2}))?\nPriority\s*:\s*([0-9])\nDescription\s*:\s*(.+)$/', $sUpdates, $aUpdates) && is_array($aUpdates)) {
        // Now update the database - new version detected.
        // 2008-02-25; 2.0-04; HOLD IT! First we need to quote this data!!!
        lovd_magicQuote($aUpdates);
        @mysql_query('UPDATE ' . TABLE_STATUS . ' SET update_check = "' . $sNow . '", update_version = "' . $aUpdates[1] . '", update_level = ' . $aUpdates[6] . ', update_description = "' . $aUpdates[7] . '", update_released = ' . (empty($aUpdates[5])? 'NULL' : '"' . $aUpdates[5] . '"'));
        // And back.
        lovd_magicUnquote($aUpdates);
        $_STAT['update_check'] = $sNow;
        $_STAT['update_version'] = $aUpdates[1];
        if (!empty($aUpdates[5])) {
            $_STAT['update_released'] = $aUpdates[5];
        }
        $_STAT['update_level'] = $aUpdates[6];
        $_STAT['update_description'] = $aUpdates[7];

    } else {
        // Error during update check.
        lovd_writeLog('MySQL:Error', 'CheckUpdate', 'Could not parse upstream server output:' . "\n" . $sUpdates);
        @mysql_query('UPDATE ' . TABLE_STATUS . ' SET update_check = "' . $sNow . '", update_version = "Error", update_level = 0, update_description = "", update_released = NULL');
        $_STAT['update_check'] = $sNow;
        $_STAT['update_version'] = 'Error';
        $_STAT['update_released'] = '';
        $_STAT['update_level'] = 0;
        $_STAT['update_description'] = '';
    }
}



// Process...
if ($_STAT['update_version'] == 'Error') {
    $sType = 'error';
    $sMessage = 'An error occured while checking for updates. For more information, see the error log. Please try again later.';

} elseif (lovd_calculateVersion($_STAT['update_version']) > lovd_calculateVersion($_SETT['system']['version'])) {
    $sType = 'newer';
    $sMessage = 'There is an update to LOVD available. More information is below.<BR>' . "\n" .
                '<B>Latest version</B>: ' . $_STAT['update_version'] . '<BR>' . "\n" .
                (empty($_STAT['update_released'])? '' :
                '<B>Release date</B>: ' . $_STAT['update_released'] . '<BR>' . "\n") .
                '<B>Priority level</B>: ' . $_SETT['update_levels'][$_STAT['update_level']] . '<BR>' . "\n" .
                '<B>Release info</B>: ' . $_STAT['update_description'] . '<BR>' . "\n" .
                '<B>Download</B>: <A href="' . dirname($_SETT['update_URL']) . '/download.php?version=' . $_STAT['update_version'] . '&amp;type=tar.gz">GZIPped TARball</A> or <A href="' . dirname($_SETT['update_URL']) . '/download.php?version=' . $_STAT['update_version'] . '&amp;type=zip">ZIP archive</A><BR>' . "\n" .
                '<A href="' . $_SETT['upstream_URL'] . $_SETT['system']['tree'] . '/changelog.txt" target="_blank">See the changelog</A>' . "\n";

} else {
    $sType = 'newest';
    $sMessage = 'There are currently no updates. Your LOVD installation is completely up to date.';
}





// If we're requested to show the icon, we will do that and quit. Else we will provide some info.
if (isset($_GET['icon'])) {
    // Create icon.
    header('Content-type: image/png');
    readfile('gfx/lovd_update_' . $sType . '_blue.png');
    exit;

} else {
    // Print what we know about new versions...
    require ROOT_PATH . 'inc-top-clean.php';
    
    // 2009-02-25; 2.0-16; Added "check now" option.
    print('      <TABLE border="0" cellpadding="2" cellspacing="0" width="100%" class="info" style="font-size : 11px;">' . "\n" .
          '        <TR>' . "\n" .
          '          <TD valign="top" align="center" width="40"><IMG src="gfx/lovd_update_' . $sType . '.png" alt="' . ucfirst($sType) . '" title="' . ucfirst($sType) . '" width="32" height="32" hspace="4" vspace="4"></TD>' . "\n" .
          '          <TD valign="middle">Last checked for updates ' . date('Y-m-d H:i:s', strtotime($_STAT['update_check'])) . ' (<A href="' . $_SERVER['PHP_SELF'] . '?force_check=' . md5($_STAT['update_check']) . '">check now</A>)<BR>' . "\n" .
          '            ' . str_replace("\n", "\n" . '            ', $sMessage) . '</TD></TR></TABLE>' . "\n\n");
    
    require ROOT_PATH . 'inc-bot-clean.php';
}
?>