<?php
/*******************************************************************************
 *
 * LOVD DATABASE OPERATOR FILE
 *
 * Created     : 2006-05-01
 * Modified    : 2011-03-29
 * For LOVD    : 2.0-31
 *
 * Access      : Curators and up.
 * Purpose     : Check LOVD download site for updates of LOVD.
 *
 * Copyright   : 2004-2010 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'];
    // 2010-06-24; 2.0-27; Some variables will be sent over POST now, because of the size limit that GET has.
    $sPOSTVars = '';

    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());
    $sPOSTVars .= ($sPOSTVars? '&' : '') . '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'));
        $sPOSTVars .= '&submitter_count=' . $nSubs;

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

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

        // Number of unique variants.
        $nUniqueVariants = 0;
        $nVariants = 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 WHERE `' . $sMutationCol . '` NOT IN ("c.=", "c.0")'));
            }
            $nUniqueVariants += $n;

            // Number of variants.
            if ($_CURRDB->colExists('Patient/Times_Reported')) {
                $sQ = 'SELECT SUM(p.`Patient/Times_Reported`) FROM ' . TABLE_PATIENTS . ' AS p LEFT JOIN ' . TABLE_PAT2VAR . ' AS p2v USING (patientid)';
            } else {
                $sQ = 'SELECT COUNT(*) FROM ' . TABLE_PAT2VAR . ' AS p2v';
            }
            $sQ .= ' LEFT JOIN ' . TABLEPREFIX . '_' . $sSymbol . '_variants AS v USING (variantid) WHERE p2v.symbol = "' . $sSymbol . '" AND `' . $sMutationCol . '` NOT IN ("c.=", "c.0")';
            list($n) = mysql_fetch_row(mysql_query($sQ));
            $nVariants += $n;
            $sGeneList .= ($sGeneList? ',' : '') . $sSymbol;
        }
        $sPOSTVars .= '&uniquevariant_count=' . $nUniqueVariants;
        $sPOSTVars .= '&variant_count=' . $nVariants;
    }

    if ($_CONF['send_listings']) {
        // Fetch install directory and gene listings.
        $sPOSTVars .= '&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);
        }
        $sPOSTVars .= '&install_dir=' . rawurlencode($sInstallDir);

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

        // 2010-06-28; 2.0-27; Send gene edit dates, curator names, emails & institutes as well.
        // This is not very efficient, but for something done once a day it will do.
        // FIXME; All this code can be made more efficient with GROUP_CONCAT, but that's not available for all LOVDs.
        $aData = array('genes' => array(), 'users' => array());
        $aUserIDs = array(); // Temporary array for query purposes only.
        // FIXME; we have a problem with an installation that has info in TABLE_CURATES that does not match the TABLE_USERS contents. How to fix that?
        // First, get the gene info (we store date last updated and curator ids).
        $q = mysql_query('SELECT g.symbol, g.gene, g.id_omim_disease, g.updated_date, u2g.userid FROM ' . TABLE_DBS . ' AS g LEFT OUTER JOIN ' . TABLE_CURATES . ' AS u2g USING (symbol) WHERE u2g.show_order > 0 ORDER BY g.symbol, u2g.show_order');
        while ($z = mysql_fetch_assoc($q)) {
            if (empty($aData['genes'][$z['symbol']])) {
                $aData['genes'][$z['symbol']] =
                         array(
                                'gene_name' => $z['gene'],
                                'diseases' => array(),
                                'updated_date' => $z['updated_date'],
                                'curators' => array($z['userid']));

                if ($z['id_omim_disease']) {
                    $aOMIM = explode("\r\n", $z['id_omim_disease']);
                    foreach ($aOMIM as $sOMIM) {
                        preg_match('/^([0-9]+) (.+)$/', $sOMIM, $aRegs);
                        $aData['genes'][$z['symbol']]['diseases'][$aRegs[1]] = $aRegs[2];
                    }
                }

            } else {
                $aData['genes'][$z['symbol']]['curators'][] = $z['userid'];
            }
            $aUserIDs[] = $z['userid'];
        }
        // Then, get the actual curator data (name, email, institute).
        $q = @mysql_query('SELECT userid, name, email, institute FROM ' . TABLE_USERS . ' WHERE userid IN (' . implode(',', array_unique($aUserIDs)) . ') ORDER BY userid');
        while ($z = @mysql_fetch_assoc($q)) {
            $aData['users'][$z['userid']] = array('name' => $z['name'], 'email' => $z['email'], 'institute' => $z['institute']);
        }
        $sData = serialize($aData);
        $sPOSTVars .= '&data=' . rawurlencode($sData);

        // 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));
        $sPOSTVars .= '&allow_index_wiki=' . (int) $bAllowIndex;
    }

    // Contact upstream.
    // 2010-06-24; 2.0-27; We no longer support a simple file_get_contents() because we now need to send POST data.
    $aOutput = lovd_php_file($_SETT['update_URL'] . $sURLVars, false, $sPOSTVars);
    // 2010-08-03; 2.0-29; Check if output is valid.
    if (is_array($aOutput)) {
        $sUpdates = implode("\n", $aOutput);
    } else {
        $sUpdates = '';
    }

    $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';
}
?>