<?php # -*- PHP -*-
# Provide an URL with a valid filename that browsers will use (save as...)
#
# Copyright (C) 2001-2002 Laurent Julliard, CodeX Team, Xerox
# Copyright (C) 2002-2005 Mathieu Roy <yeupou--gnu.org>
# Copyright (C) 2007  Sylvain Beucler
# Copyright (C) 2017, 2018, 2020  Ineiev
#
# This file is part of Savane.
#
# Savane is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Savane 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

$GLOBALS['skip_csp_headers'] = 1;

require_once('include/init.php');
require_once('include/http.php');

extract(sane_import('request', array('file_id')));

if ($file_id == 'test.png')
  {
    header('Content-Type: image/png');
    $fname = $GLOBALS['sys_www_topdir'] . '/images/common/floating.png';
    header('Content-Length: ' . stat($fname)['size']);
    readfile ($fname);
    exit (0);
  }

# Check if the provided file_id is a valid numerical id.
if (!$file_id || !ctype_digit($file_id))
  exit_missing_param();

# Check privacy of the item this file is attached to and reject access by
# non-authorized users.

$result = db_execute("SELECT item_id, artifact FROM trackers_file WHERE file_id=?",
                     array($file_id));

if ($result && db_numrows($result) > 0)
  {
    $item_id  = db_result($result, 0, 'item_id');
    $artifact = db_result($result, 0, 'artifact');
  }
else
# TRANSLATORS: the argument is file id (a number).
  util_die (sprintf(_("File #%s not found"), htmlspecialchars($file_id)));

# TRANSLATORS: the argument is artifact ID.
if (!ctype_alnum($artifact))
  util_die(sprintf(_('Invalid artifact %s'),
                   '<em>' . htmlspecialchars($artifact) . '</em>'));
$result = db_execute("SELECT group_id, privacy FROM $artifact WHERE bug_id=?",
                     array($item_id));

if ($result && db_numrows($result) > 0)
  {
    $group_id = db_result($result, 0, 'group_id');
    if ((db_result($result, 0, 'privacy') == '2')
        && !member_check_private(0, $group_id))
      exit_error(_("Non-authorized access to file attached to private item"));
  }

$result = db_execute("SELECT description,filename,filesize,filetype,date "
                     . "FROM trackers_file WHERE file_id=? LIMIT 1",
                     array($file_id));

$vex = $result && db_numrows($result) > 0;

if ($vex && db_result($result, 0, 'filesize') >= 0)
  {
    $mtime = db_result ($result, 0, 'date');
    http_exit_if_not_modified($mtime);
    header('Last-Modified: ' . date('r', $mtime));

    # Check if the file is not empty.
    # This should have been checked before, but it is harmless to check it
    # one more time.
    if (db_result($result, 0, 'filesize') == 0)
      exit_error(_("Nothing in here, file is empty"));

    # Check if the filename in database match with the one in the URL.
    # We do not want to allow broken URL that may make a user download
    # a file with a given name like "myimage.png" when actually downloading
    # something completely different like "mystupidvirus.scr".
    if (db_result($result, 0, 'filename')
        != basename(rawurldecode($_SERVER['PHP_SELF'])))
      {
        exit_error(
_("The filename in the URL does not match the filename registered in the database"));
      }

    $path = $sys_trackers_attachments_dir . '/' . $file_id;
    if (!is_readable($path))
      exit_error(_("No access to the file."));

    # Download the patch with the correct filetype.
    header('Content-Type: ' . db_result($result, 0, 'filetype'));
    header('Content-Length: ' . db_result($result, 0, 'filesize'));
    header('Content-Disposition: attachment; filename='
           . db_result($result, 0, 'filename'));
    header('Content-Description: ' . db_result($result, 0, 'description'));
    # Dump file to the browser.
    readfile($sys_trackers_attachments_dir . '/' . $file_id);
  }
else
  {
    if (!$vex)
      exit_error(sprintf(_("Couldn't find attached file #%s."),
                         htmlspecialchars ($file_id)));

    exit_error(sprintf(_("Attached file #%s was lost."),
                         htmlspecialchars ($file_id)) . " "
               . sprintf(_("File attributes: name '%s', size %s, type '%s', date %s."),
                         htmlspecialchars(db_result ($result, 0, 'filename')),
                         htmlspecialchars(db_result ($result, 0, 'filesize')),
                         htmlspecialchars(db_result ($result, 0, 'filetype')),
                         utils_format_date(db_result ($result, 0, 'date'))));
  }
?>
