<?php 
// bug.php - All the interactions with a bug/file
// ------------------------------------------------------------------------
// Copyright (c) 2001, 2002 The phpBugTracker Group
// Copyright (c) 2004, 2005 David Han Sze Chuen, Denis Guinnepain for Air Liquide Medical Systems (Taema)
// Copyright (c) 2005, 2006, 2015 Denis Guinnepain
 
// ------------------------------------------------------------------------
// This file is part of Diamentis

// Diamentis 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.

// Diamentis 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 phpBugTracker; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// ------------------------------------------------------------------------

include 'include.php';
include 'attachment_lib.php';
include 'exportpdf.php';
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// View the votes for a bug
function vote_view($bug_id) {
	global $u, $db, $t, $STRING;

	$t->assign('votes', $db->getAll('select login, v.created_date ' . 'from ' . TBL_AUTH_USER . ' u, ' . TBL_BUG_VOTE . " v " . "where u.user_id = v.user_id and bug_id = $bug_id " . 'order by v.created_date'));
	$t->wrap('bugvotes.html', 'bugvotes');
} 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Add a vote to a bug to (possibly) promote it
/*
function vote_bug($bug_id) {
	global $u, $db, $now, $_pv, $STRING; 
	// Check to see if the user already voted on this bug
	if ($db->getOne("select count(*) from " . TBL_BUG_VOTE . " where bug_id = $bug_id and user_id = $u")) {
		show_bug($bug_id, array('vote' => $STRING['already_voted']));
		return;
	} 
	// Check whether the user has used his allotment of votes (if there is a max)
	if (MAX_USER_VOTES and $db->getOne("select count(*) from " . TBL_BUG_VOTE . " where user_id = $u") >= MAX_USER_VOTES) {
		show_bug($bug_id, array('vote' => $STRING['too_many_votes']));
		return;
	} 
	// Record the vote
	$db->query("insert into " . TBL_BUG_VOTE . " (user_id, bug_id, created_date)
		values ($u, $bug_id, $now)"); 
	// Proceed only if promoting by votes is turned on
	if (PROMOTE_VOTES) {
		// Has this bug already been promoted?
		$bug_is_new = $db->getOne("select count(*) from " . TBL_BUG . " b, " .
			TBL_STATUS . " s where bug_id = $bug_id and b.status_id = s.status_id and
			status_name = 'New'"); 
		// If a number of votes are required to promote a bug, check for promotion
		if (!$bug_is_new and $db->getOne("select count(*) from " .
				TBL_BUG_VOTE . " where bug_id = $bug_id") == PROMOTE_VOTES) {
			$status_id = BUG_PROMOTED;
			$buginfo = $db->getOne("select * from " . TBL_BUG . " where bug_id = $bug_id");
			$changedfields = array('status_id' => $status_id);
			do_changedfields($u, $buginfo, $changedfields);
		} 
	} 
	if (isset($_pv['pos'])) {
		$posinfo = "&pos={$_pv['pos']}";
	} else {
		$posinfo = '';
	} 
	header("Location: bug.php?op=show&bugid=$bug_id$posinfo");
} 
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Beautify the bug comments
function format_comments($comments) {
	global $me;
	$rev="toto"; 
sscanf($comments, "%d\t%s %s", $id, $first, $last);
	// Set up the regex replacements
	$patterns = array(
		'/(bug|' . APPLICATION_NAME . '|File)[[:space:]]*(#?)([0-9]+)/i', // matches bug #nn
		'/r([0-9]+)/i', // matches bug #nn
		'/cvs:([^\.\s:,!\/\\\\]+)[\/\\\\]+([^\.\s:,\?!]+(\.[^\.\s:,\?!]+)*)(:)?(\d\.[\d\.]+)+/i', // matches cvs:CVSROOT_NAME/filename.php or matches cvs:CVSROOT_NAME/filename.php:n.nn
		'/cvs:([^\.\s:,!\/\\\\]+)[\/\\\\]+([^\.\s:,\?!]+(\.[^\.\s:,\?!]+)*)(:)?([\w]*)?/i' // matches cvs:CVSROOT_NAME/filename.php or matches cvs:CVSROOT_NAME/filename.php:n.nn
	);
	$replacements = array(
		"\\1 <a href='$me?op=show&file_id=\\3'>\\2\\3</a>", // internal link to bug
		'<a href="' . CVS_WEB . 'listing.php?repname=PA+repository&path=%2F&rev=$1&sc=1" target="_new"> r\\1 </a>', // external link to svn web interface
		'<a href="' . CVS_WEB . '\\2?rev=\\5&cvsroot=\\1" target="_new">\\2</a>', // external link to cvs web interface
		'<a href="' . CVS_WEB . '\\2?only_with_tag=\\5&cvsroot=\\1" target="_new">\\2</a>' // external link to cvs web interface
		);
	$comments2=preg_replace($patterns, $replacements, $comments);
	return preg_replace('/myprevrev/i',intval($rev)-1, $comments2);
	
} 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Show the activity for a bug
function show_history($bugid) {
	global $db, $t, $STRING, $QUERY;

	if (!is_numeric($bugid)) {
		show_text($STRING['nobughistory']);
		return;
	} 

	$t->assign('history', $db->getAll(sprintf($QUERY['bug-history'], $bugid)));
	$t->wrap('bughistory.html', 'bughistory');
} 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Send the email about changes to the bug and log the changes in the DB
// NOTE : this function is unused
// FM Number	Author		Version	Date		Contents
// FM 274 	D. Guinnepain 	V1.05	2004/02/16	Add status in the Object field of the sent mail
/*
function do_changedfields($userid, &$buginfo, $cf = array(), $comments = '') {
	global $db, $t, $u, $select, $now, $STRING, $QUERY; 
	// It's a new bug if the changedfields array is empty and there are no comments
	$newbug = (!count($cf) and !$comments); 
	// FM1248 david.han-sze-chuen@airliquide.com 21/07/04 title has to be filtered, but not the url
	if (isset($cf['title']))
		$cf['title'] = htmlspecialchars($cf['title']);

	$template = $newbug ? 'bugemail-newbug.txt' : 'bugemail.txt';
	foreach(array('title', 'url') as $field) {
		if (isset($cf[$field])) {
			$db->query('insert into ' . TBL_FILE_HISTORY . ' (bug_id, changed_field, old_value, new_value, created_by, created_date)' . " values (" . join(', ', array($buginfo['bug_id'], $db->quote($field),
						$db->quote(stripslashes($buginfo[$field])),
						$db->quote(stripslashes($cf[$field])), $u, $now)) . ")");
			$t->assign(array($field => stripslashes($cf[$field]),
					$field . '_stat' => '!'
					));
		} else {
			$t->assign(array($field => stripslashes($buginfo[$field]),
					$field . '_stat' => ' '
					));
		} 
	} 
	// create array with tablenames for following loop
	$cfgDatabase = array('project' => TBL_PROJECT,
		'component' => TBL_COMPONENT,
		'status' => TBL_STATUS,
		'resolution' => TBL_RESOLUTION,
		'database' => TBL_DATABASE,
		'severity' => TBL_SEVERITY,
		'os' => TBL_OS,
		'version' => TBL_VERSION,
		'database' => TBL_DATABASE,
		'site' => TBL_SITE
		);

	foreach($cfgDatabase as $field => $table) {
		if (isset($buginfo[$field . '_id'])) {
			$oldvalue = $db->getOne("select ${field}_name from $table" . " where ${field}_id = {$buginfo[$field.'_id']}");
		} 
		if (empty($oldvalue)) $oldvalue = 'None';

		if (isset($cf[$field . '_id'])) {
			$newvalue = $db->getOne("select ${field}_name from $table" . " where ${field}_id = {$cf[$field.'_id']}");
			if (empty($newvalue)) $newvalue = 'None';

			$db->query('insert into ' . TBL_FILE_HISTORY . ' (bug_id, changed_field, old_value, new_value, created_by, created_date)' . " values (" . join(', ', array($buginfo['bug_id'], $db->quote($field),
						$db->quote(stripslashes($oldvalue)),
						$db->quote(stripslashes($newvalue)), $u, $now)) . ")");
			$t->assign(array($field . '_id' => stripslashes($newvalue),
					$field . '_id_stat' => '!'
					));
			if ($field == 'status') {
				$status_name = $newvalue;
			} ;
		} else {
			$t->assign(array($field . '_id' => stripslashes($oldvalue),
					$field . '_id_stat' => ' '
					));
			if ($field == 'status') {
				$status_name = $oldvalue;
			} ;
		} 
	} 
	// Handle versions other than version
	$versions = array ('to_be_closed_in_version' => 'to be closed in version',
		'closed_in_version' => 'closed in version');

	foreach($versions as $field => $field_name) {
		if (isset($buginfo[$field . '_id'])) {
			$oldvalue = $db->getOne('select version_name from ' . $cfgDatabase['version'] . ' where version_id = ' . $buginfo[$field . '_id']);
		} 
		if (empty($oldvalue)) $oldvalue = 'None';

		if (isset($cf[$field . '_id'])) {
			$newvalue = $db->getOne('select version_name from ' . $cfgDatabase['version'] . ' where version_id = ' . $cf[$field . '_id']);
			if (empty($newvalue)) $newvalue = 'None';

			$db->query('insert into ' . TBL_FILE_HISTORY . ' (bug_id, changed_field, old_value, new_value, created_by, created_date)' . " values (" . join(', ', array($buginfo['bug_id'], $db->quote($field_name),
						$db->quote(stripslashes($oldvalue)),
						$db->quote(stripslashes($newvalue)), $u, $now)) . ")");
			$t->assign(array($field . '_id' => stripslashes($newvalue),
					$field . '_id_stat' => '!'
					));
		} else {
			$t->assign(array($field . '_id' => stripslashes($oldvalue),
					$field . '_id_stat' => ' '
					));
		} 
	} 
	// FM1466 david.han-sze-chuen@airliquide.com 16/09/2004
	// check that email notification is authorized
	if (!isset($_POST['suppress_email']) || $_POST['suppress_email'] != 1) {
		// Reporter never changes
		$reporter = $db->getOne('select email from ' . TBL_AUTH_USER . " u, " . TBL_USER_PREF . " p where u.user_id = {$buginfo['created_by']} " . "and u.user_id = p.user_id and email_notices = 1");
		$reporterstat = ' ';
		$assignedto = $db->getOne('select email from ' . TBL_AUTH_USER . " u, " .
			TBL_USER_PREF . ' p where u.user_id = ' .
			(!empty($cf['assigned_to']) ? $cf['assigned_to'] : $buginfo['assigned_to']) . " and u.user_id = p.user_id and email_notices = 1");
		$assignedtostat = !empty($cf['assigned_to']) ? '!' : ' '; 
		// If there are new comments grab the comments immediately before the latest
		if ($comments or $newbug) {
			$rs = $db->limitQuery('select u.login, c.comment_text, c.created_date' . ' from ' . TBL_COMMENT . ' c, ' . TBL_AUTH_USER . ' u' . " where bug_id = {$buginfo['bug_id']} and c.created_by = u.user_id" . ' order by created_date desc', 0, 2);
			$rs->fetchInto($row);
			$t->assign(array('newpostedby' => $row['login'],
					'newpostedon' => date(TIME_FORMAT, $row['created_date']) . ' on ' .
					date(DATE_FORMAT, $row['created_date']),
					'newcomments' => textwrap('+ ' . format_comments($row['comment_text']), 72, "\n+ ")
					)); 
			// If this comment is the first additional comment after the creation of the
			// bug then we need to grab the bug's description as the previous comment
			if ($rs->numRows() < 2) {
				list($by, $on, $comments) = $db->getRow('select u.login, b.created_date, b.description' . ' from ' . TBL_BUG . ' b, ' . TBL_AUTH_USER . ' u' . " where b.created_by = u.user_id and bug_id = {$buginfo['bug_id']}",
					null, DB_FETCHMODE_ORDERED);
				$t->assign(array('oldpostedby' => $by,
						'oldpostedon' => date(TIME_FORMAT, $on) . ' on ' . date(DATE_FORMAT, $on),
						'oldcomments' => textwrap(format_comments($comments), 72)
						));
			} else {
				$rs->fetchInto($row);
				$t->assign(array('oldpostedby' => $row['login'],
						'oldpostedon' => date(TIME_FORMAT, $row['created_date']) . ' on ' .
						date(DATE_FORMAT, $row['created_date']),
						'oldcomments' => textwrap(format_comments($row['comment_text']), 72)
						));
			} 
			$t->assign('showcomments', true);
		} else {
			$t->assign('showcomments', false);
		} 

		$maillist = array(); 
		// Don't email the person who just made the changes (later, make this
		// behavior toggable by the user)
		if ($userid != $buginfo['created_by'] and !empty($reporter)) {
			$maillist[] = $reporter;
		} 
		if ($userid != (!empty($cf['assigned_to']) ? $cf['assigned_to'] : $buginfo['assigned_to'])
				and !empty($assignedto)) {
			$maillist[] = $assignedto;
		} 
		// Collect the CCs
		if ($ccs = $db->getCol(sprintf($QUERY['bug-cc-list'], $buginfo['bug_id']))) {
			$maillist = array_merge($maillist, $ccs);
		} 
		// Later add a watcher (such as QA person) check here
		if (count($maillist)) {
			if ($toemail = delimit_list(', ', $maillist)) {
				$t->assign(array('eMail_Comment1' => $STRING['eMail_Comment1'],
						'eMail_Comment2' => $STRING['eMail_Comment2'],
						'bugid' => $buginfo['bug_id'],
						'bugurl' => INSTALL_URL . "/bug.php?op=show&bugid={$buginfo['bug_id']}",
						'priority' => $select['priority'][(!empty($cf['priority']) ? $cf['priority'] : $buginfo['priority'])],
						'priority_stat' => !empty($cf['priority']) ? '!' : ' ',
						'email_reporter' => $STRING['BUGDISPLAY']['reporter'],
						'email_Summary' => $STRING['BUGDISPLAY']['summary'],
						'email_URL' => $STRING['BUGDISPLAY']['url'],
						'email_Product' => $STRING['BUGDISPLAY']['project'],
						'email_Version' => $STRING['BUGDISPLAY']['version'],
						'email_toBeClosedVersion' => $STRING['BUGDISPLAY']['tobeclosedinversion'],
						'email_ClosedVersion' => $STRING['BUGDISPLAY']['closedinversion'],
						'email_Component' => $STRING['BUGDISPLAY']['component'],
						'email_Subsystem' => $STRING['BUGDISPLAY']['site'],
						'email_Status' => $STRING['BUGDISPLAY']['status'],
						'email_Resolution' => $STRING['BUGDISPLAY']['resolution'],
						'email_Severity' => $STRING['BUGDISPLAY']['severity'],
						'email_Level' => $STRING['BUGDISPLAY']['os'],
						'email_Support' => $STRING['BUGDISPLAY']['database'],
						'email_Priority' => $STRING['BUGDISPLAY']['priority'],
						'email_AssignedTo' => $STRING['BUGDISPLAY']['assignedto'],
						'email_Comments' => $STRING['BUGDISPLAY']['comments'],
						'email_PostedBy' => $STRING['BUGDISPLAY']['postedby'],
						'email_at' => $STRING['BUGDISPLAY']['date'],
						'reporter' => $reporter,
						'reporter_stat' => $reporterstat,
						'assignedto' => $assignedto,
						'assignedto_stat' => $assignedtostat
						)); 
				// $bugid2=$buginfo['bug_id'];
				// $buginfo2 = $db->getRow("select * from ".TBL_BUG." where bug_id =$bugid2");
				// $status_id2 = $buginfo2['status_id'];
				// $status_Row = $db->getRow("select * from ".TBL_STATUS." where status_id = $status_id2 ");
				// $status_name = $status_Row['status_name'];
				qp_mail($toemail,
					"[Bug {$buginfo['bug_id']}] " . ($newbug ? 'New' : 'Changed') . ' - ' .
					stripslashes(
						// david.han-sze-chuen : 8/7/2004 : FM1157
						htmlspecialchars_decode(!empty($cf['title']) ? $cf['title'] : $buginfo['title'])
						)
					 . ' - ' . "$status_name",
					$t->fetch($template),
					sprintf("From: %s\nReply-To: %s\nErrors-To: %s", ADMIN_EMAIL, ADMIN_EMAIL, ADMIN_EMAIL));
			} 
		} 
	}
} // end of do_changedfields($userid, &$buginfo, $cf = array(), $comments = '')
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// / FM Number	Author		Version	Date		Contents
// / FM 278 	D. Guinnepain 	V1.05	2004/02/16	Add the possibility de close the bug (order 7) for the status order 2 or 3.
function update_bug($file_id, $verbose = false) {
	global $db, $t, $u, $STRING, $perm, $now, $_pv, $primary_input_array, $QUERY, $ERROR, $HTTP_SESSION_VARS;
	
	/*
	if($verbose) {
		println("update_bug() : function started");
	}
	*/
	
	// check param
	$file_id = intval($file_id);
	$file_id = abs($file_id);
	
	if (!isset($_POST[$primary_input_array]) || !is_array($_POST[$primary_input_array])) {
		death('ERROR', '01 update_bug() : post data is missing.');
	}
	$comments = &$_POST['comments'];
	
	$project_id = MPFile::getProject_id($file_id);
	//$mpfile = &new MPFile($project_id);
	$mpfile = new MPFile($project_id);
	$field_conf = &$mpfile->project_field_properties;
	
	// get the original file data
	$original = $mpfile->getFile($file_id);
	$original = current($original);
	$posted_values = $_POST[$primary_input_array];
	//$changed_fields = array(); // changed fields : key=field_name, value=new value
	
	$changed_fields = treat_dynamic_input_data($posted_values, $mpfile, $original, $verbose);
	
	if ($verbose) {
		println("changed_fields = ");
		printarray($changed_fields);
	}	
	
	$projectinfo = $db->getRow("select * from " . TBL_PROJECT . " where project_id = $project_id");
	
	// Should we allow changes to be made to this bug by this user?
	if (STRICT_UPDATING and !(in_array($u, $original['assigned_to']['value']) /* !($u == $buginfo['assigned_to'] */ 
		or ($u == $original['created_by']['value']) or $perm->have_perm('Editbug'))) {
		show_bug($file_id, array('status' => $STRING['bugbadperm']));
		return;
	}
	
	// if the user isn't a project admin
	if (!$perm->have_perm('Admin') && !($perm->have_project_perm($project_id,'Admin'))) { 
	/* no : configure it with reserved values	// only the project admin should be able to set to close status
		if (isset($changed_fields['status_id']) 
			&& in_array($changed_fields['status_id'], $mpfile->getSv_ids_by_option(OPTION_CLOSED))) {
			show_bug($file_id, array('status' => $STRING['bugbadstatus']));
			return;
		}
	*/	
		// some selectbox values are reserved
		$reserved_selectbox_sv_ids = $mpfile->getSv_ids_by_option(OPTION_RESERVED);
		foreach($changed_fields as $field_name=>$v) {
			if (($mpfile->project_field_properties[$field_name]['field_type_title'] == SELECTBOX_TYPE)
				&& in_array($v, $reserved_selectbox_sv_ids)) {
				show_bug($file_id, array('status' => sprintf($ERROR['reserved_value'], 
							$mpfile->sb_cache[$v]['value'], 
							$mpfile->project_field_properties[$field_name]['title']
						)
					)
				);
				/*
				death('ERROR', 
					sprintf($ERROR['reserved_value'], 
							htmlspecialchars($mpfile->sb_cache[$v]['value']), 
							htmlspecialchars($mpfile->project_field_properties[$field_name]['title'])
					)
				);
				*/
				return;
			}
		}
	}
		
	// if project is modified
	$file_to_be_moved=false;
	if (isset($changed_fields['project_id'])) {		
		// Should we allow project change to be made to this bug ?
		$project_id_old = &$original['project_id']['value'];
		$project_id_new = &$changed_fields['project_id'];
	
		if (($project_id_new != $project_id_old) and !($perm->have_project_perm($project_id_old,'Admin'))) {
			show_bug($file_id, array('status' => $STRING['bugbadproject']));
			return;
		}
		// A comment should be added
		if ($comments == "") {
			show_bug($file_id, array('status' => $STRING['bugbadcomment_project']));
			return;
		}
		$file_to_be_moved=true;
		//remove old file
		
	}
	// if status is modified
	if (isset($changed_fields['status_id'])) {		
		// Should we allow status change to be made to this bug ?
		$status_id_old = &$original['status_id']['value'];
		$sort_order_old = $mpfile->sb_cache[$status_id_old]['order'];
		$status_id_new = &$changed_fields['status_id'];
		$sort_order_new = $mpfile->sb_cache[$status_id_new]['order'];
	
		//$status_old = $db->getRow("select * from " . TBL_STATUS . " where status_id = $status_id_old ");
		//$sort_order_old = $status_old['sort_order'];
		//$status_new = $db->getRow("select * from " . TBL_STATUS . " where status_id = $status_id ");
		//$sort_order_new = $status_new['sort_order'];
		//println("tableau de sb_cache");
		//printarray($mpfile->sb_cache);
		$sequenceFree=in_array('sequenceFree', $mpfile->sb_cache[$status_id_old]['options']);
		//println($sequenceFree);
		if (($sort_order_new > ($sort_order_old + 1)) and $projectinfo['sequence'] and ($sequenceFree!=true)) {
			show_bug($file_id, array('status' => $STRING['bugbadstatus']));
			return;
		}
		//println("sort_order_new = $sort_order_new");
		//println("sort_order_old = $sort_order_old");
		//println("comments = $comments");
	
		// A comment should be added
		if ($sort_order_new != $sort_order_old and $comments == "" and HIDE_COMMENTS == 0) {
			show_bug($file_id, array('status' => $STRING['bugbadcomment']));
			return;
		}
	}
	 
	// Check for more than one person modifying the bug at the same time
	if ($_POST['last_modified_date'] != $original['last_modified_date']['value']) {
		if ($_POST['last_modified_date']!="ever")  // not applicable in case of multiple update
		{
			show_bug($file_id, array('status' => $STRING['datecollision']));
		return;
		}
	}
	
	$cc_type = null;
	$contact_id = null;
	// Add CC if specified
	if ($_POST['add_cc']) {
		if (!$cc_uid = $db->getOne("select user_id from " . TBL_AUTH_USER . " where login = " . $db->quote(stripslashes($_POST['add_cc'])))) {
			show_bug($file_id, array('status' => $STRING['nouser']));
			die();
			return;
		} 
		$cc_already = $db->getOne('select user_id from ' . TBL_BUG_CC . " where bug_id = $file_id and user_id = $cc_uid");
		// if not already in contacts and the contact_id is not the creator of this file
		if (!$cc_already && $cc_uid != $original['created_by']['value']) {
			$db->query("insert into " . TBL_BUG_CC . " (bug_id, user_id, created_by,
				created_date)  values ($file_id, $cc_uid, $u, $now)");
			$cc_type = 'add';
			$contact_id = $cc_uid;
		}
	}
	// Remove CCs if requested
	if (isset($_POST['remove_cc']) and count($_POST['remove_cc'])) {
		$res = $db->query('delete from ' . TBL_BUG_CC . " where bug_id = $file_id and user_id in (" .
			implode(', ', $_POST['remove_cc']) . ')');
		if ($db->affectedRows()) {
			$cc_type = 'del';
			$contact_id = $_POST['remove_cc'];
		}
	} 
	
	$dependency_type = null;
	$dependency_id = null;
	// Add dependency if requested
	if (!empty($_POST['add_dependency'])) {
		$add_dependency = &$_POST['add_dependency'];
		$add_dependency = preg_replace('/\D/', '', $add_dependency); 
		// Validate the bug number
		if (!is_numeric($add_dependency)) {
			show_bug($file_id, array('add_dep' => $STRING['nobug']));
			return;
		} 
		if (!$db->getOne('select count(*) from ' . TBL_FILE_INDEX . " where file_id = $add_dependency")) {
			show_bug($file_id, array('add_dep' => $STRING['nobug']));
			return;
		} 
		// if it's a dependency to the same file_id
		if ($add_dependency == $file_id) {
			show_bug($file_id, array('add_dep' => $STRING['self_dependency_forbidden']));
			return;
		}
		
		// Check if the dependency has already been added
		if ($db->getOne('select count(*) from ' . TBL_BUG_DEPENDENCY . " where bug_id = $file_id and depends_on = $add_dependency")) {
			show_bug($file_id, array('add_dep' => $STRING['dupe_dependency']));
			return;
		} 
		// Add it
		$dependency_type = 'add';
		$dependency_id = $add_dependency;
		$db->query("insert into " . TBL_BUG_DEPENDENCY . " (bug_id, depends_on) values($file_id, $add_dependency)");
	} 
	// Remove dependency if requested
	if (!empty($_POST['del_dependency'])) {
		$del_dependency = &$_POST['del_dependency'];
		$del_dependency = preg_replace('/\D/', '', $del_dependency);
		if (is_numeric($del_dependency)) {
			$db->query("delete from " . TBL_BUG_DEPENDENCY . " where bug_id = $file_id and depends_on = $del_dependency");
		} 
		$dependency_type = 'del';
		$dependency_id = $del_dependency;
	} 

	if ($_POST['comments']) {
		$comments = &$_POST['comments'];
		$status_name = null;
		if (isset($changed_fields['status_id'])) {
			$status_name = $mpfile->sb_cache[$changed_fields['status_id']]['value'];
		} else {
			$status_name = $mpfile->sb_cache[$original['status_id']['value']]['value'];
		}
		$state=$original['status_id']['field_conf']['title'];
		$comments2 = "$state $status_name : \n " . stripslashes($comments);
		insert_comment($file_id, $comments2, $verbose);		
	}
	


	if (count($changed_fields) or !empty($comments)) 
	{
		// TODO : update the do_changefields() function
		// do_changedfields($u, $original, $changed_fields, $comments);
		if ($file_to_be_moved)
		{
			$mpfile->deleteFile($file_id);
	        //$mpfile = &new MPFile($project_id_new);
	        $mpfile = new MPFile($project_id_new);
	        $original_compact=array();
			foreach ($original as $a_field)
		   	{
				$original_compact[$a_field['field_conf']['field_name']]=$a_field['value'];
		   	}
		   	$mpfile->insertFile($original_compact, $verbose,true);

		//domain admin are notified for the change
			$subject=sprintf($STRING['eMail_moved_in_file'],$file_id);
			$content=sprintf($STRING['eMail_moved_file_by_user'],$file_id,$HTTP_SESSION_VARS['uname']);
			$content.=INSTALL_URL . "/bug.php?op=show&file_id=$file_id";
			mailtoDomainAdmin($project_id_new,$subject,$content);
			$subject=sprintf($STRING['eMail_moved_out_file'],$file_id);
			$content=sprintf($STRING['eMail_moved_file_by_user'],$file_id,$HTTP_SESSION_VARS['uname']);
			$content.=INSTALL_URL . "/bug.php?op=show&file_id=$file_id";
			mailtoDomainAdmin($project_id,$subject,$content);
		
		}
//println("original");
//printarray($original);
		$mpfile->updateFile($file_id, $changed_fields, $verbose);
		log_into_history($original, $changed_fields, $dependency_type, $dependency_id, $cc_type, $contact_id, $verbose);
		if (!isset($_POST['suppress_email']) || $_POST['suppress_email'] != 1) {
			notify_by_mail($file_id, $mpfile, array_keys($changed_fields), $newbug = false, $verbose);
		}
	} 
} // end of update_bug($file_id)
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
	Insert a comment into DB. Sets creation date automatically
	@param integer $file_id the file id
	@param string $comment the comment text
	@param boolean $verbose print debug info
	@return void
*/
function insert_comment($file_id, $comment, $verbose = false) {
	global $db, $now, $u;
	
	$sql = "insert into " . TBL_COMMENT . " (comment_id, bug_id, comment_text, created_by, created_date)" 
		. " values (" . $db->nextId(TBL_COMMENT) . ", $file_id, " . $db->quote($comment) . ", $u, $now)";
	if ($verbose) {
		println(nl2br(htmlspecialchars("insert_comment() : sql = $sql")));
	}
	$db->query($sql);
} // end of insert_comment($file_id, $comment, $verbose = false)
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
	Treat the submitted data from a file insert form.
*/
function insert_bug($project_id, $verbose = false) {
	//global $db, $me, $u, $_pv, $_gv, $STRING, $now, $HTTP_POST_FILES, $HTTP_SERVER_VARS;
	global $db, $t, $me, $u, $STRING, $now, $primary_input_array, $QUERY, $perm;

	// println("insert_bug()");
	// check some params
	$project_id = intval($project_id);
	//$mpfile = &new MPFile($project_id); // if the mpfile creation fails, a problem has occured
	$mpfile = new MPFile($project_id); // if the mpfile creation fails, a problem has occured
	$field_conf = &$mpfile->project_field_properties;
	$sp = &$mpfile->sp_cache;
	if(!isset($_POST[$primary_input_array]) || !is_array($_POST[$primary_input_array])) {
		death('ERROR', '01 insert_bug() : primary input data is missing in the post variables.');
	}
	$p_values = &$_POST[$primary_input_array];
	
	// some fields must have been set :
	// description
//	if (!isset($p_values['description']) || (strlen(trim($p_values['description'])) == 0)) {
//		death('ERROR', '02 insert_bug() : you must write a description to enter a file.');
//	}
	// title
//	if (!isset($p_values['title']) || (strlen(trim($p_values['title'])) == 0)) {
//		death('ERROR', '03 insert_bug() : you must write a title to enter a file.');
//	}
	// if assigned_to is not set, set the file to the project admins
	if (!isset($p_values['assigned_to']) || !is_array($p_values['assigned_to'])) {
		$p_values['assigned_to'] = array();
		$sql = sprintf($QUERY['get_project_admin_user_ids'], $db->quote($project_id));
		
		if($verbose) {
			println("insert_bug() : get project amdin user ids : sql = $sql");
		}
		
		foreach($db->getAll($sql) as $v) {
			$p_values['assigned_to'][] = $v['user_id'];
		}
	}
	
	// filter some values
	$defined_fields = treat_dynamic_input_data($p_values, $mpfile, $original = null, $verbose);
//println("defined_fields");
//printarray($defined_fields);
//println("p_values");
//printarray($p_values);
//println("original");
//printarray($original);
//die;
	// if the user isn't a project admin
	if (!$perm->have_perm('Admin') && !($perm->have_project_perm($project_id,'Admin'))) { 
		// some selectbox values are reserved
		$reserved_selectbox_sv_ids = $mpfile->getSv_ids_by_option(OPTION_RESERVED);
		foreach($defined_fields as $field_name => $v) {
			if (($mpfile->project_field_properties[$field_name]['field_type_title'] == SELECTBOX_TYPE)
				&& in_array($v, $reserved_selectbox_sv_ids)) {
				show_bug($file_id, array('status' => sprintf($ERROR['reserved_value'],
							$mpfile->sb_cache[$v]['value'], 
							$mpfile->project_field_properties[$field_name]['title']
						)
					)
				);
				/*
				death('ERROR', 
					sprintf($ERROR['reserved_value'], 
							htmlspecialchars($mpfile->sb_cache[$v]['value']), 
							htmlspecialchars($mpfile->project_field_properties[$field_name]['title'])
					)
				);
				*/
			}
		}
	}
	
	if($verbose) {
		println('insert_bug() : file creation values ');
		printarray($defined_fields);
	}
	
	$file_id = $mpfile->insertFile($defined_fields, $verbose);

	notify_by_mail($file_id, $mpfile, array(), $newbug = true, $verbose);
	
	// no need to insert a comment just for the description	
	// $new_comment = &$defined_fields['description'];
	// $new_comment = "$STRING[description_of_file] :\n$new_comment";
	// insert_comment($file_id, $new_comment, $verbose);
	
	if (isset($_FILES['attachment']) and $_FILES['attachment']['name'] != '') {
		add_attachment($file_id, $_POST['attachment']['description']);
	} 
	$t->assign('informText', $STRING['file_validation'] );
	$t->assign('file_id', $file_id ); 
	$t->wrap("created_file.html");
	//header("Location: index.php");
} // end of insert_bug($project_id)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
	Prepare a file insert form for Smarty
	old name : show_form()
*/
function show_insert_form($project_id, $error = '') {
	global $db, $t, $system_read_only_field_names, $system_hidden_field_names;

	//$mpfile = &new MPFile($project_id);
	$mpfile = new MPFile($project_id);
	$field_conf = $mpfile->project_field_properties;
	// DG adding the following line to get order
	$field_conf = order_by_element_of_array('edit_order', 'asc', $field_conf); 

	if ($file_id && $error) {
		$t->assign($_POST);
		$t->assign(
			array(
				'error' => $error,
				'project_id' => $project_id,
				'projectname' => $mpfile->project_data['project_name']
			)
		);
	}
	$system_not_declared_field_names=array();
	$hidden_field_names=array();
	foreach ($field_conf as $FieldName)
	{
		// subproperties
		$prop = & $mpfile->sp_cache[$FieldName['field_name']];
		if ($prop->declare==false)
		{
			$system_not_declared_field_names[]=$FieldName['field_name'];
		}
		if ($prop->hidden==true)
		{
			$hidden_field_names[]=$FieldName['field_name'];
		}
		$field_conf_clean[$FieldName['field_name']]=$FieldName;
	}
	

	// filter out some fields
	$filtered_field_conf = array_diff_key($field_conf_clean, array_flip($system_hidden_field_names));
	$filtered_field_conf = array_diff_key($filtered_field_conf, array_flip($hidden_field_names));
	$filtered_field_conf = array_diff_key($filtered_field_conf, array_flip($system_read_only_field_names));
	$filtered_field_conf = array_diff_key($filtered_field_conf, array_flip($system_not_declared_field_names));
	// remove the project_id, status_id and the closed date
	$filtered_field_conf = array_diff_key($filtered_field_conf, array_flip(array('project_id', 'status_id', 'closed_date', 'assigned_to')));
	
	$t->assign(
		array(
			'mpfile' => $mpfile,
			'string' => STRING_TYPE,
			'field_conf' => $mpfile->project_field_properties,
			'filtered_conf' => $filtered_field_conf
		)
	);	
	
	$t->assign('max_size', ATTACHMENT_MAX_SIZE);
	$t->assign('no_attachments', HIDE_ATTACHMENTS);
	
	$t->wrap('bugform.html');
} // end of show_insert_form($file_id = 0, $error = '')
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
// unused
function show_bug_printable($file_id) {
	global $db, $me, $t, $QUERY, $restricted_projects;

	list($mpfile, $field_conf, $fc_filtered, $file) = MPFile::getFile_kit($file_id, array('description'), 'edit_order', 'asc');
	
	$t->assign(
		array(
			'attachments' => $attachments,
			'comments' => $db->getAll('select comment_text, c.created_date, login from ' . TBL_COMMENT . ' c, ' . TBL_AUTH_USER . 
				" where bug_id = $file_id and c.created_by = user_id order by c.created_date")
		)
	);
	
	return;
	
	if (!is_numeric($file_id) or
			!$row = $db->getRow(sprintf($QUERY['bug-printable'], $file_id,
					$restricted_projects))) {
		show_text($STRING['bugbadnum'], true);
		exit;
	} 

	$t->assign($row);
	$t->assign(array('bug_dependencies' => delimit_list(', ', $db->getCol('select ' .
					db_concat("'<a href=\"$me?op=show&file_id='", 'depends_on', '\'">#\'',
						'depends_on', '\'</a>\'') . ' from ' . TBL_BUG_DEPENDENCY . " where bug_id = $file_id"))
			)); 
			
	
	
	// Show the comments
	$t->assign('comments', $db->getAll('select comment_text, c.created_date, login' . ' from ' . TBL_COMMENT . ' c, ' . TBL_AUTH_USER . " where bug_id = $file_id and c.created_by = user_id order by c.created_date"
			));
	$t->wrap('bugdisplay-printable.html', 'viewbug');
} // end of show_bug_printable
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Grab the links for the previous and next bugs in the list
function prev_next_links($bugid, $pos) {
	global $dsn, $_sv, $QUERY, $t, $query_db_fields, $db_headers;
	// DEBUG
	// echo "prev_next_links(bugid = $bugid, pos = $pos); <br>
	// order = ". $_sv['queryinfo']['order'] .
	// "<hr>"; 
	// echo "\$_SESSION[queryinfo]<br>";
	// foreach($_sv['queryinfo'] as $h => $va) {
	// echo "[$h] = $va <br>\n";
	// } 
	// Create a new db connection because of the limit query affecting later queries
	$db = DB::Connect($dsn);
	if (DB::isError($db)) {
		die($db->message . '<br>' . $db->userinfo);
	} 
	$db->setOption('optimize', 'portability');
	$db->setErrorHandling(PEAR_ERROR_CALLBACK, "handle_db_error");

	if (!isset($_sv['queryinfo']['query']) || !$_sv['queryinfo']['query']) {
		return array('', '');
	} 

	if ($pos) {
		$offset = $pos - 1;
		$limit = 2;
	} else {
		$offset = 0;
		$limit = 1;
	} 
	// FM398 D.HSC 22/06/2004
	$desired_fields = array();
	$desired_fields[] = 'bug_id';
	$desired_fields[] = 'reporter';
	$desired_fields[] = 'owner';

	if (($_sv['queryinfo']['order'] != 'bug_id') && // "order" must not be in these fields
			($_sv['queryinfo']['order'] != 'reporter') && // because it's already in the query by default
			($_sv['queryinfo']['order'] != 'owner')) {
		foreach($db_headers as $k => $v) { // though, it must be a valid db field name
			if ($v == $_sv['queryinfo']['order']) {
				// $additional_query_fields = ', ' . $query_db_fields[$k];
				$desired_fields[] = $k;
				break;
			} 
		} 
	} 
	// echo "desired fields : <br>";
	// printarray($desired_fields);
	// echo "<hr><br>";
	// echo "\$_sv['queryinfo']['order'] : <br>";
	// printarray($_sv['queryinfo']['order']);
	// echo "<hr><br>";
	$theQuery = list_items_query_builder($desired_fields, $_sv['queryinfo']['order'], $_sv['queryinfo']['sort'], ACTION_SHOW_BUG); 
	// DEBUG
	// echo "\$theQuery before => <pre>$theQuery</pre> <hr><br>";
	// echo "\$theQuery after => <pre>$theQuery</pre> <hr><br>";
	$theQuery = sprintf($theQuery, "and bug_id <> $bugid"); 
	// DEBUG FM398 D.HSC 21/06/2004
	// echo "SQL request : " . sprintf($QUERY['bug-prev-next'],
	// "<b>" . $additional_query_fields . "</b>",
	// "<b>" . $_sv['queryinfo']['query'] . "</b>",
	// "<font color=red>" . $bugid . "</font>",
	// "<b>" . $_sv['queryinfo']['order'] . "</b>",
	// "<font color=green>" . $_sv['queryinfo']['sort'] . "</font>"). "<br><hr>";
	$rs = $db->limitQuery(
		// sprintf(
		// $QUERY['bug-prev-next'],
		// $additional_query_fields,
		// $_sv['queryinfo']['query'],
		// $bugid,
		// $_sv['queryinfo']['order'],
		// $_sv['queryinfo']['sort']
		// ),
		$theQuery,
		$offset,
		$limit);

	list($firstid, $chunks) = $rs->fetchRow();
	list($secondid, $chunks) = $rs->fetchRow();
	// print_r($temp1 = $rs->fetchRow());
	// echo "<br>";
	// print_r($temp2 = $rs->fetchRow());
	// echo "<br>";
	// print_r($rs->fetchRow());
	// echo "<br>";
	// list($firstid, $chunks) = $temp1;
	// list($secondid, $chunks) = $temp2;
	// DEBUG
	// echo "firstid = $firstid | chunks = $chunks<br>
	// secondid = $secondid | chunks = $chunks <br>";
	if ($pos) {
		if ($firstid) {
			$t->assign(array('prevbug' => $firstid, 'prevpos' => $pos - 1));
		} 
		if ($secondid) {
			$t->assign(array('nextbug' => $secondid, 'nextpos' => $pos + 1));
		} 
	} else {
		if ($firstid) {
			$t->assign(array('nextbug' => $firstid, 'nextpos' => $pos + 1));
		} 
	} 
} //end of prev_next_links($bugid, $pos)
///////////////////////////////////////////////////////////////////////////////////////////////////
/**
	Prepare the template to print a file edit form.
*/
function show_bug($file_id, $error = array(), $printable_view = false, $verbose = false) {
	global $db, $me, $t, $STRING, $TITLE, $u, $_gv, $_pv, $QUERY, $restricted_projects, $system_hidden_field_names, $primary_input_array;
	
	list($mpfile, $field_conf, $fc_filtered, $file) = MPFile::getFile_kit($file_id, null, 'edit_order', 'asc');
	//list($mpfile, $field_conf, $fc_filtered, $file) = MPFile::getFile_kit($file_id, array('description'), 'edit_order', 'asc');
	
	if ($verbose) {
		println("show_bug() : project_id = $project_id");
		println("show_bug() : file_id = $file_id");
		println("show_bug() : mpfile = $mpfile");
		println("show_bug() : file = $file");
		// printarray($file);
	}	
	
	// if there is an error, input values are supposed to be in $error[$primary_input_array]
	// if (!empty($error) && !empty($error[$primary_input_array]) && is_array($error[$primary_input_array])) {
	//		$t->assign('primary_input_array' => $primary_input_array);
	// }
	
	// DEBUG
	//TODO previous, next links
	//prev_next_links($bugid, isset($_gv['pos']) ? $_gv['pos'] : 0);
	
	// get the list of contacts
	// $contact_list = array();
	$ccl = array();
	$sql = "SELECT u.user_id, u.first_name, u.last_name, u.email FROM " . TBL_BUG_CC . " c, " 
		. TBL_AUTH_USER . " u WHERE u.user_id = c.user_id AND c.bug_id = " . $db->quote($file_id) . " order by first_name, last_name";
	foreach($db->getAll($sql) as $v) {
		$ccl[] = $v;
		/*
		if ($printable_view) {
			$contact_list[$v['user_id']] = "{$v['first_name']} {$v['last_name']} <a href=\"mailto:" . htmlspecialchars($v['email']) . "\">" 
				. htmlspecialchars("<{$v['email']}>") . "</a>";
		} else {
			$contact_list[$v['user_id']] = $v['first_name'] . ' ' . $v['last_name'];
		}
		*/
	}
	
	$t->assign('contact_list', $ccl);
	/*
	if (count($contact_list)) {
		if ($printable_view) {
			$list_of_cc = implode('<br>', $contact_list);
		} else {
			$list_of_cc = listbox('remove_cc', $contact_list, 11, $multiple = true, null);
		}
	} else {
		$list_of_cc = false;
	}
	*/
	
	// Override the database values with posted values if there were errors
	if (count($error)) {
		$t->assign($_POST);
		
		// just do a one dimension filter
		$filtered_input = array();
		foreach($_POST[$primary_input_array] as $k => $v) {
			if (!is_array($v)) {
				$filtered_input[$k] = stripslashes($v);
			} else {
				$filtered_input[$k] = $v;
			}
		}
		
		// println("filtered input : ");
		// printarray($filtered_input);
		$t->assign('previous_comment', $_POST['comments']);
		$t->assign('primary_input_array', $filtered_input);
	}
// determine if some fields have to be hidden for display in the current state
	$fieldnames_to_filter = array();
	foreach ($fc_filtered as $k=>$v)
	{
		if (is_array($mpfile->sp_cache[$k]->hidden_fields) && in_array($file['status_id']['value'],$mpfile->sp_cache[$k]->hidden_fields))
		{
			$mpfile->sp_cache[$k]->hidden_fields=true;
			if (WF_HIDE_IS_REMOVE==1)
			{
				$fieldnames_to_filter[]=$k;
			}
		}
		else
		{
			$mpfile->sp_cache[$k]->hidden_fields=false;
		}
	}
	$fc_filtered = array_diff_key($fc_filtered, array_flip($fieldnames_to_filter));
	if (EXPLODE_STATES==1)
	{
//printarray($fc_filtered);
		$mpfile->sp_cache['status_id']->read_only=true;
//		$fc_filtered = array_diff_key($fc_filtered, array_flip(array('status_id')));
	}
	$t->assign(
		array(
			'mpfile' => $mpfile,
			'field_conf' => $field_conf,
			'fc_filtered' => $fc_filtered,
			'file' => $file,
			'project_id' => $project_id,
			'error' => $error,
			'string' => STRING_TYPE,
			'no_comments' => HIDE_COMMENTS,
			'no_attachments' => HIDE_ATTACHMENTS,
			'flg_wkfw' => USE_WORKFLOW ,
			'flg_explode' => EXPLODE_STATES,
			'list_of_cc' => $list_of_cc,
			'already_voted' => $db->getOne("select count(*) from " . TBL_BUG_VOTE . " where bug_id = $file_id and user_id = $u"),
			'num_votes' => $db->getOne("select count(*) from " . TBL_BUG_VOTE . " where bug_id = $file_id"),
			'bug_dependencies' => delimit_list(', ', $db->getCol('select ' .
					db_concat("'<a href=\"$me?op=show&file_id='", 'depends_on', '\'">#\'',
						'depends_on', '\'</a>\'') . ' from ' . TBL_BUG_DEPENDENCY . " where bug_id = $file_id"))
		)
	); 
	/////////////////////////
	// Show the attachments
	/////////////////////////
	$attachments = array();
	$rs = $db->query("select * from " . TBL_ATTACHMENT . " where bug_id = $file_id");
	
	if ($rs->numRows()) {
		while ($rs->fetchInto($att)) {
			// I don't know why is_readable keeps failing even when the file is readable. So, I remove this check.
			//if (is_readable(ATTACHMENT_PATH . "/{$project_id}/$file_id-{$att['file_name']}")) {
				$attachments[] = $att;				
			//}
		}
	}
	
	if($verbose) {
		println("show_bug() : number of file attachments : " . $rs->numRows());
		println("show_bug() : attachments = ");
		printarray($attachments);
	}
	
	///////////////////////
	// Show the comments
	///////////////////////
	$t->assign(
		array(
			'attachments' => $attachments,
			'comments' => $db->getAll('select comment_text, c.created_date, login from ' . TBL_COMMENT . ' c, ' . TBL_AUTH_USER . 
				" where bug_id = $file_id and c.created_by = user_id order by c.created_date")
		)
	);

	$value=$file['status_id']['value'];
	$selectbox_values = $mpfile->getSelectboxValues(intval($field_conf['status_id']['field_conf_id'])); 
	// filter out some data
	$sb_values = array();
	$sb_titles = array();
	if ($allow_void) 
	{
		$sb_values['void'] = '';
		$sb_titles['void'] = $STRING['no_selected_value'];
	} 
	// reaffect the sv_id in the array
	foreach($selectbox_values as $k => $v) 
	{
		$selectbox_values[$k]['sv_id'] = $k;
	}
					
	$selectbox_values = order_by_element_of_array('order', 'asc', $selectbox_values);
	$project_id = MPFile::getProject_id($file_id);
	$sequence=$db->getOne("SELECT sequence FROM " . TBL_PROJECT . " WHERE project_id = $project_id");;
	if (USE_WORKFLOW==1 )
	{
		$res = $db->getOne($do_query="SELECT `sv_description` FROM " . TBL_SELECTBOX_VALUE . " WHERE `sv_id` = " . $value);
		if(DB::isError($res))
		{
			echo ("<br>Error : " . $res->getMessage() . "<br>");
			print($do_query . "<br>");
			die();
		}
		$res=unserialize($res);
	}
	elseif ($sequence==1) //if sequence order is important
	{
		$ref_order=1+$db->getOne("SELECT sv_order FROM " . TBL_SELECTBOX_VALUE . " WHERE sv_id=$value");
	}
	foreach($selectbox_values as $v) 
	{
		if ($v['sv_id']==$value                                           || 
			   ( (USE_WORKFLOW==1 && !in_array($v['sv_id'],$res) ) ||
			     ($sequence==1 && $v['order']<=$ref_order        )   )  )
		{
			if ($v['sv_id']==$value)
			{
				$sb_values[$v['sv_id']]['name'] = $STRING['BUGDISPLAY']['submitIdle'];
			}
			else
			{
				$sb_values[$v['sv_id']]['name'] = htmlspecialchars($v['value']);
			}
			$sb_values[$v['sv_id']]['id'] = $v['sv_id'];
		}
	} 
	$t->assign('next_states',$sb_values);



	if ($printable_view) {
		//$t->wrap('bugdisplay-printable.html');
		print_single_file($file_id);
	} else {
		$t->wrap('bugdisplay.html');
	}
} // end of show_bug($file_id, $error = array())
///////////////////////////////////////////////////////////////////////////////////////////////////

function edit_multi($field_conf_id,$project_id=PUBLIC_PROJECT_ID,$verbose)
{
	global $db, $t, $STRING;
	
	//$mpfile = &new MPFile($project_id); 
	$mpfile = new MPFile($project_id); 
	$field_conf = $mpfile->project_field_properties; 
	$field_name = $mpfile->getField_property_by_another_property('field_name',
				$searched_data = array('field_conf_id' => $field_conf_id));
	$t->assign('mpfile',$mpfile);
	$t->assign('k',$field_name);
	$t->assign('v',$field_conf[$field_name]);
	$t->wrap('multipleedit.html');
} //end of edit_multi()

function update_list_bug( $_selected_files_array , $verbose)
{
	global $db, $t, $STRING;
	
//	printarray($_selected_files_array);
	foreach ($_selected_files_array as $file_id=>$value)
	{
	update_bug($file_id);
	}
} //end of edit_multi()


/**
	Prepare a list of project's names for smarty.
*/
function show_projects() {
	global $db, $t, $STRING, $perm, $restricted_projects, $_gv,$u; 
	
	$perm_Edit=$db->getOne("SELECT perm_id FROM " . TBL_AUTH_PERM . " WHERE perm_name='Editbug'");
	// Show only active projects with at least one component
	if ($perm->have_perm('Admin')) { // Show admins all projects
		$p_query = '';
		$p_from = '';
	} elseif (isset($u) && $u!=0) 
	{ // Filter out projects that can't be seen by this user
		//$p_query = " and p.project_id not in ($restricted_projects)"; // note : the public project should be in the restricted projects
		$p_from=', ' . TBL_PROJECT_PERM . ' pp ';
		$p_query= " ) AND ((p.share_new<>0  ) OR (p.project_id=pp.project_id AND pp.user_id=$u AND pp.perm_id<=$perm_Edit) ";
	} 
	else
	{
		$p_from='';
		$p_query= " ) AND ((p.share_new<>0  )  ";
	}
	
//	$p_query .= " AND p.project_id != " . PUBLIC_PROJECT_ID;
	
	$projects = array();
	$projects = $db->getAll('select distinct p.project_id, p.project_name, p.project_desc, p.created_date from ' . TBL_PROJECT 
		. ' p ' . $p_from . " where (p.active = 1 AND p.project_id != " . PUBLIC_PROJECT_ID .  $p_query . ') order by project_name');

	switch (count($projects)) {
		case 0 :
			show_text(htmlspecialchars($STRING['noprojects']), true);
			return;
		case 1 :
			$perm->verify_perm(intval($projects[0]['project_id']),'New');
			show_insert_form(intval($projects[0]['project_id']));
			break;
		default :
			$t->assign('projects', $projects);
			$t->wrap('projectlist.html', 'enterbug');
	} 
} // end of show_projects()
/**
	Create an email to send to file's contacts and its creator.	
*/
// function notify_by_mail($comments, $file, $mpfile, $verbose) {
function notify_by_mail($file_id, $mpfile, $changed_field_names, $newbug = false, $verbose) {
	global $db, $t, $u, $now, $QUERY, $STRING;

	if ($verbose) {
		println("notify_by_mail() : start");
	}
	
	if (is_string($file_id)) {
		$file_id = intval($file_id);
	}
	if (!is_numeric($file_id)) {
		death('ERROR', '01 notify_by_mail() : file_id is invalid.');
	}

	if ($changed_field_names == null) {
		$changed_field_names = array();
	} elseif (!is_array($changed_field_names)) {
		death('ERROR', '02 notify_by_mail() : variable \$changed_field_names must be an array.');
	}
	
	$project_id = null;
	$file = null;
	if ($mpfile == null) { // if there's no mpfile, create it
		$project_id = MPFile::getProject_id($file_id);
		//$mpfile = &new MPFile($project_id);
		$mpfile = new MPFile($project_id);
		$file = $mpfile->getFile($file_id);			
	} else {
		$file = $mpfile->getFile($file_id);			
		$project_id = &$file['project_id']['value'];
	}
	$file = $file[$file_id];
	
	$created_by = $file['created_by']['value'];
	$assigned = $mpfile->getAssignation($file_id);
	
	$emails  = array();
	
	// Email for the reporter
	$sql = 'SELECT email FROM ' . TBL_AUTH_USER . " u, " . TBL_USER_PREF . " p WHERE u.user_id = "
		. $db->quote($created_by) . " AND u.user_id = p.user_id AND email_notices = 1 AND u.user_id != " . $db->quote($u);
		// with this last condition, it prevents the user to be notified by its own bug modifications
	if ($verbose) {
		println("notify_by_mail() : sql = $sql");
	}
	$emails['reporter'] = $db->getOne($sql);
	
	$emails['assigned_users'] = array();
	// Emails for the assigned users
	if (count($assigned)) {
		$sql = 'SELECT email FROM ' . TBL_AUTH_USER . " u, " . TBL_USER_PREF 
			. " p WHERE u.user_id IN (" . implode(', ', $assigned) . ") AND u.user_id = p.user_id AND email_notices = 1 AND u.user_id != " . $db->quote($u);
		foreach($db->getAll($sql) as $v) {
			$emails['assigned_users'][] = $v['email'];
		}
	}
	
	// Collect the file contacts' emails
	if ($ccs = $db->getCol(sprintf($QUERY['bug-cc-list'], $file_id))) {
		$emails['contacts'] = $ccs;
	}
	
	// don't email the submitter of the mail
	// TODO : implement this feature if you want ^^;
	
	// gather all emails into one string
	$toemail = array();
	foreach($emails as $email_group) {
		if (is_array($email_group)) {
			foreach($email_group as $email) {
				$toemail[$email] = $email;
			}
		} else {
			$toemail[$email_group] = $email_group;
		}
	}
	$toemail = implode(', ', $toemail);
	
	// get the 2 last comments
	$rs = $db->limitQuery('SELECT u.login, u.email, u.first_name, u.last_name, c.comment_text, c.created_date FROM ' . TBL_COMMENT . ' c, ' 
		. TBL_AUTH_USER . " u WHERE bug_id = {$file_id} AND c.created_by = u.user_id  ORDER BY comment_id DESC", 0, 2);
	$tab = fetchAll($rs);
	
	$comments = array();
	foreach($tab as $row) {
		$comments[] = array(
			'posted_by' => "{$row['first_name']} {$row['last_name']} <{$row['email']}>",
			'posted_on' => date(DATE_FORMAT_DETAILED, $row['created_date']),
			'comment' => textwrap('+ ' . $row['comment_text'], 72, "\n+ ")
		);
	}
	
	$comments = array_reverse($comments);
	
	// prepare some mail params
	$subject = "[FM#$file_id] " . ($newbug ? $STRING['MAIL']['new_file'] : $STRING['MAIL']['changed_file']) 
		. " - {$file['title']['value']} - {$file['status_id']['selectbox']['value']}";
	$subject = htmlspecialchars($subject);
	//$headers = "MIME-Version: 1.0\n";
	//$headers .= "Content-type: text/html; charset=WINDOWS-1255\n";
	$headers = sprintf("From: %s\nReply-To: %s\nErrors-To: %s", ADMIN_EMAIL, ADMIN_EMAIL, ADMIN_EMAIL);
	
	//DEBUG
	// print all info before sending mail
	if ($verbose) {
		println("\$toemail = $toemail");
		println("\$subject = $subject");
		println("\$headers = $headers");
	}
	
	// prepare the template
	$field_conf = &$mpfile->project_field_properties;
	// filter out
	$fc_filtered = filter_fields($field_conf, array('description'), 'edit_order', 'asc');
	
	// the changed fields must be highlighted
	$changed = array_intersect_key(array_flip(array_keys($fc_filtered)), array_flip($changed_field_names));
	foreach($changed as $k => $v) {
		$changed[$k] = true;
	}
	
	//printarray($changed);
	//printarray(array_keys($fc_filtered));
	// printarray(array_flip($changed_field_names));
	
	$t->assign(array(
		'file' => $file,
		'changed' => $changed,
		'fc' => $fc_filtered,
		'mpfile' => $mpfile,
		'description' => ($newbug)? $file['description']['value'] : false,
		'comments' => $comments,
		'eMail_Comment1' => $STRING['eMail_Comment1'],
		'eMail_Comment2' => $STRING['eMail_Comment2'],
		'file_url' => INSTALL_URL . "/bug.php?op=show&file_id={$file['bug_id']['value']}",
		)
	);
	//DEBUG
	// $t->wrap('bugemail.txt');
	
	qp_mail($toemail, $subject, $t->fetch('bugemail.txt'), $headers);
	
	if ($verbose) {
		println("notify_by_mail() : stop");
	}
} // end of notify_by_mail($file_id, $mpfile, $verbose)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if ($op) {
	switch ($op) {
		case 'history':
			$perm->verify_perm_file($_GET['file_id'],'View');
			show_history($_GET['file_id']);
			break;
		case 'add':
//			$perm->check('Editbug');
			if (isset($_GET['project'])) {
				$perm->verify_perm($_GET['project'],'New');
				show_insert_form(intval($_GET['project']));
			} else {
				show_projects();
			} 
			break;
		case 'show':
			$perm->verify_perm_file($_GET['file_id'],'View');
			show_bug($_GET['file_id'], null, false, $verbose);
			break;
		case 'update':
			$perm->verify_perm_file($_POST['file_id'],'Editbug');
			update_bug($_POST['file_id'], $verbose);
			$file_id=$_POST['file_id'];
			header("Location: bug.php?op=show&file_id=$file_id");
			break;
		case 'updtlst':
			//$perm->verify_perm_file($_POST['file_id'],'Editbug');
			update_list_bug( $_SESSION['queryinfo']['sel'], $verbose);
			//header("Location: bug.php?op=show&file_id=$file_id");
			break;
		case 'edit_multi':
			// $perm->verify_perm_file($_POST['file_id'],'Editbug');
			//printarray($_SESSION['queryinfo']['sel']);die;
			//printarray($_POST);die;
			if (isset($_POST['modify']))
			{
				add_selected_file_ids($_POST['sel'],$_POST['sel_stct']);
				edit_multi($_POST['FieldToUpdate'],$_SESSION['queryinfo']['domain_id'], $verbose);
			}
			elseif (isset($_POST['remember']))
			{
				add_selected_file_ids($_POST['sel'],$_POST['sel_stct']);
				header("Location: query.php?op=redoquery");
			}
			elseif (isset($_POST['erase']))
			{
				unset($_SESSION['queryinfo']['sel']);
				header("Location: query.php?op=redoquery");
			}
			elseif (isset($_POST['save']))
			{
				add_selected_file_ids($_POST['sel'],$_POST['sel_stct']);
				$selection=array();
				foreach ($_SESSION['queryinfo']['sel'] as $k=>$v)
				{
					$selection[$k]=$k;
				}
				header("Location: query.php?domain=1&primary_input%5Bbug_id%5D=". implode ("%2C",$selection) ."&cmptype%5Bbug_id%5D=one_element&meet_all_conditions=1&stat_field=project_id&weight_field=project_id&ChartSelect=isPie&order=project_id&sort=asc&savedqueryname=". $_POST['savedqueryname'] ."&op=doquery&savedqueryoverride=0");
			}
				
			break;
		case 'do':
			$perm->verify_perm($_POST['project_id'],'New');
			insert_bug($_POST['project_id']);
			break;
		case 'print':
			// show_bug_printable($_GET['file_id']);
			$perm->verify_perm_file($_GET['file_id'],'View');
			show_bug($_GET['file_id'], null, true, $verbose);
			break;
		case 'vote':
			vote_bug($_GET['file_id']);
			break;
		case 'viewvotes':
			vote_view($_GET['file_id']);
			break;
	} 
} else {
	header("Location: query.php");
} 

?>