<?php
/*
+ ----------------------------------------------------------------------------+
|     e107 website system
|
|     ©Steve Dunstan 2001-2002
|     http://e107.org
|     jalist@e107.org
|
|     Released under the terms and conditions of the
|     GNU General Public License (http://gnu.org).
|
|     $Source: /cvs_backup/e107_0.8/usersettings.php,v $
|     $Revision: 1.24 $
|     $Date: 2008-03-17 20:45:29 $
|     $Author: e107steved $
+----------------------------------------------------------------------------+

Notes:
Uses $udata initially, later curVal to hold current user data
Admin log events:
	USET_01 - admin changed user data

*/


require_once("class2.php");
require_once(e_HANDLER."ren_help.php");
require_once(e_HANDLER."user_extended_class.php");
$ue = new e107_user_extended;

//define("US_DEBUG",TRUE);
define("US_DEBUG",FALSE);


if (!USER) 
{	// Must be logged in to change settings
  header("location:".e_BASE."index.php");
  exit;
}

if (!ADMIN && e_QUERY && e_QUERY != "update") 
{
  header("location:".e_BASE."usersettings.php");
  exit;
}

require_once(e_HANDLER."ren_help.php");

if(is_readable(THEME."usersettings_template.php"))
{
  include_once(THEME."usersettings_template.php");
}
else
{
  include_once(e_THEME."templates/usersettings_template.php");
}
include_once(e_FILE."shortcode/batch/usersettings_shortcodes.php");

require_once(e_HANDLER."calendar/calendar_class.php");
$cal = new DHTML_Calendar(true);
$_uid = is_numeric(e_QUERY) ? intval(e_QUERY) : "";
$sesschange = '';						// Notice removal
$photo_to_delete = '';
$avatar_to_delete = '';
$changed_user_data = array();

require_once(HEADERF);


// Given an array of user data, return a comma separated string which includes public, admin, member classes etc as appropriate.
function addCommonClasses($udata)
{
  $tmp = array();
  if ($udata['user_class'] != "") $tmp = explode(",", $udata['user_class']);
  $tmp[] = e_UC_MEMBER;
  $tmp[] = e_UC_READONLY;
  $tmp[] = e_UC_PUBLIC;
  if($udata['user_admin'] == 1)
  {
	$tmp[] = e_UC_ADMIN;
  }
  if (strpos($udata['user_perms'],'0') === 0)
  {
	$tmp[] = e_UC_MAINADMIN;
  }
  return implode(",", $tmp);
}


// Save user settings (changes only)
//-----------------------------------
$error = "";

if (isset($_POST['updatesettings']))
{
	if(!varsettrue($pref['auth_method']) || $pref['auth_method'] == '>e107')
	{
	  $pref['auth_method'] = 'e107';
	}

	if($pref['auth_method'] != 'e107')
	{
	  $_POST['password1'] = '';
	  $_POST['password2'] = '';
	}


	if ($_uid && ADMIN)
	{	// Admin logged in and editing another user's settings - so editing a different ID
	  $inp = $_uid;
	  $remflag = TRUE;
	}
	else
	{	// Current user logged in - use their ID
	  $inp = USERID;
	}


	$udata = get_user_data($inp);				// Get all the existing user data, including any extended fields
	$udata['user_classlist'] = addCommonClasses($udata);

	$peer = ($inp == USERID ? false : true);
/*
	echo "<pre>";
	var_dump($udata);
	echo "</pre>";
*/


	// Check external avatar
	if ($_POST['image'])
	{
	  $_POST['image'] = str_replace(array('\'', '"', '(', ')'), '', $_POST['image']);   // these are invalid anyway, so why allow them? (XSS Fix)
	  if ($size = getimagesize($_POST['image']))
	  {
		$avwidth = $size[0];
		$avheight = $size[1];
		$avmsg = "";

		$pref['im_width'] = varsettrue($pref['im_width'], 120);
		$pref['im_height'] = varsettrue($pref['im_height'], 100);
		if ($avwidth > $pref['im_width']) 
		{
		  $avmsg .= LAN_USET_1." ({$avwidth})<br />".LAN_USET_2.": {$pref['im_width']}<br /><br />";
		}
		if ($avheight > $pref['im_height']) 
		{
		  $avmsg .= LAN_USET_3." ({$avheight})<br />".LAN_USET_4.": {$pref['im_height']}";
		}
		if ($avmsg) 
		{
		  $_POST['image'] = "";
		  $error = $avmsg;
		}
		else
		{
		  if ($_POST['image'] != $udata['user_image'])
		  {
			$changed_user_data['user_image'] = $_POST['image'];
		  }
		}
	  }
	  else
	  {  // Invalid image file - we could just put up a message
	  }
	}




	// The 'class' option doesn't really make sense to me, but left it for now
//	$signup_option_title = array(LAN_308, LAN_120, LAN_121, LAN_USET_19);
//	$signup_option_names = array("realname", "signature", "image", "timezone");

	$signup_option_title = array(LAN_308, LAN_120, LAN_121, LAN_USET_6, LAN_USET_19);
	$signup_option_names = array("realname", "signature", "image", "class", 'signup_option_customtitle');
	foreach($signup_option_names as $key => $value)
	{  // Check required signup fields
		if ($pref['signup_option_'.$value] == 2 && !$_POST[$value] && !$_uid)
		{
			$error .= LAN_SIGNUP_6.$signup_option_title[$key].LAN_SIGNUP_7."\\n";
		}
    }



// Login Name checks - only admin can change login name
	if (isset($_POST['loginname']) && ADMIN && getperms("4"))
	{  // Only check if its been edited
	  $loginname = trim(preg_replace('/&nbsp;|\#|\=|\$/', "", strip_tags($_POST['loginname'])));
	  if ($loginname != $_POST['loginname'])
	  {
		$error .= LAN_USET_13."\\n";
	  }
	  // Check if login name exceeds maximum allowed length
	  if (strlen($loginname) > varset($pref['loginname_maxlength'],30))
	  {
	    $error .= LAN_USET_14."\\n";
	  }
	  if ($udata['user_loginname']  != $loginname) 
	  {
	    $changed_user_data['user_loginname']  = $loginname; 
	  }
	  else 
	  {
		unset($loginname);
	  }
	}
	if (isset($loginname)) $_POST['loginname'] = $loginname; else unset($_POST['loginname']);			// Make sure no chance of the $_POST value staying set inappropriately



	// Display name checks 
	// If display name == login name, it has to meet the criteria for both login name and display name
//	echo "Check_class: {$pref['displayname_class']}; {$udata['user_classlist']}; {$peer}<br />";
	if (check_class($pref['displayname_class'], $udata['user_classlist'], $peer))
	{	// Display name can be different to login name - check display name if its been entered
	  if (isset($_POST['username']))
	  {
	    $username = trim(strip_tags($_POST['username']));
		$_POST['username'] = $username;
//		echo "Found new display name: {$username}<br />";
	  }
	}
	else
	{  // Display name and login name must be the same - check only if the login name has been changed
	  if (varsettrue($loginname)) $username = $loginname;
	}



	if (varsettrue($username))
	{
	  // Impose a minimum length on display name
	  if (strlen($username) < 2)
	  {
		$error .= LAN_USET_12."\\n";
	  }
	  if (strlen($username) > varset($pref['displayname_maxlength'],15))
	  {
		$error .= LAN_USET_15."\\n";
	  }

	  if(isset($pref['signup_disallow_text']))
	  {
		$tmp = explode(",", $pref['signup_disallow_text']);
		foreach($tmp as $disallow)
		{
		  if(stristr($username, trim($disallow)))
		  {
			$error .= LAN_USET_11."\\n";
		  }
	    }
	  }

	// Display Name exists.
	  if ($sql->db_Count("user", "(*)", "WHERE `user_name`='".$username."' AND `user_id` != '".intval($inp)."' "))
	  {
		$error .= LAN_USET_17;
	  }
	  if ($username != $udata['user_name']) $changed_user_data['user_name'] = $username;
	  unset($username);
	}



// Password checks
	if ($_POST['password1'] != $_POST['password2']) 
	{
	  $error .= LAN_105."\\n";
	}
	else
	{
	  if(trim($_POST['password1']) != "")
	  {
		if (strlen(trim($_POST['password1'])) < $pref['signup_pass_len']) 
		{
		  $error .= LAN_SIGNUP_4.$pref['signup_pass_len'].LAN_SIGNUP_5."\\n";
		}
	    $changed_user_data['user_password'] = md5(trim($_POST['password1']));
	  }
	}


// Email address checks
	if (!varsettrue($pref['disable_emailcheck']))
	{
	  if (!check_email($_POST['email']))
	  {
		$error .= LAN_106."\\n";
	  }
	}

	// Check for duplicate of email address
	if ($sql->db_Select("user", "user_name, user_email", "user_email='".$tp -> toDB($_POST['email'])."' AND user_id !='".intval($inp)."' "))
	{
	  $error .= LAN_408."\\n";
	}

		
		
// Uploaded avatar and/or photo
	if (isset($_FILES['file_userfile']['error']))
	{
	  require_once(e_HANDLER."upload_handler.php");
	  require_once(e_HANDLER."resize_handler.php");

		if ($uploaded = file_upload(e_FILE."public/avatars/", "avatar=".$udata['user_id']))
	  {
		foreach ($uploaded as $upload)
		{	// Needs the latest upload handler (with legacy and 'future' interfaces) to work
		  if ($upload['name'] && ($upload['index'] == 'avatar') && $pref['avatar_upload'])
		  {
			// avatar uploaded - give it a reference which identifies it as server-stored
			$_POST['image'] = "-upload-".$upload['name'];
			if ($_POST['image'] != $udata['user_image'])
			{
			  $avatar_to_delete = str_replace("-upload-", "", $udata['user_image']);
//			  echo "Avatar change; deleting {$avatar_to_delete}<br />";
			  $changed_user_data['user_image'] = $_POST['image'];
			}

			if (!resize_image(e_FILE."public/avatars/".$upload['name'], e_FILE."public/avatars/".$upload['name'], "avatar"))
			{
			  unset($message);
			  $error .= RESIZE_NOT_SUPPORTED."\\n";
			  @unlink(e_FILE."public/avatars/".$upload['name']);
			  $_POST['image'] = '';
			  unset($changed_user_data['user_image']);
			}
		  }

		  if ($upload['name'] && ($upload['index'] == 'photo') && $pref['photo_upload'] )
		  {
			// photograph uploaded
			if ($udata['user_sess'] != $upload['name'])
			{
			  $photo_to_delete = $udata['user_sess'];
			  $changed_user_data['user_sess'] = $upload['name'];
			}

			if (!resize_image(e_FILE."public/avatars/".$upload['name'], e_FILE."public/avatars/".$upload['name'], 180))
			{
			  unset($message);
			  $error .= RESIZE_NOT_SUPPORTED."\\n";
			  @unlink(e_FILE."public/avatars/".$upload['name']);
			  unset($changed_user_data['user_sess']);
			}
		  }
		}
	  }
	}

// See if user just wants to delete existing photo
	if (isset($_POST['user_delete_photo']))
	{
	  $photo_to_delete = $udata['user_sess'];
	  $changed_user_data['user_sess'] = '';
//	  echo "Just delete old photo: {$photo_to_delete}<br />";
	}




    // Validate Extended User Fields.
	if($_POST['ue'])
	{
	  if($sql->db_Select('user_extended_struct'))	
	  {
		while($row = $sql->db_Fetch())
		{
		  $extList["user_".$row['user_extended_struct_name']] = $row;
		}
	  }

	  $ue_fields = "";
	  foreach($_POST['ue'] as $key => $val)
	  {
			$err = false;
			$parms = explode("^,^", $extList[$key]['user_extended_struct_parms']);
			$regex = $tp->toText($parms[1]);
			$regexfail = $tp->toText($parms[2]);
    		if(defined($regexfail)) {$regexfail = constant($regexfail);}
	  		if($val == '' && $extList[$key]['user_extended_struct_required'] == 1 && !$_uid)
			{
         		$error .= LAN_SIGNUP_6.($tp->toHtml($extList[$key]['user_extended_struct_text'],FALSE,"defs"))." ".LAN_SIGNUP_7."\\n";
	    		$err = TRUE;
			}
			if($regex != "" && $val != "")
			{
				if(!preg_match($regex, $val))
				{
               		$error .= $regexfail."\\n";
         			$err = TRUE;
	         	}
			}
			if(!$err)
			{
				$val = $tp->toDB($val);
				$ue_fields .= ($ue_fields) ? ", " : "";
				$ue_fields .= $key."='".$val."'";
				}
	  }
    }



// All key fields validated here
// -----------------------------

// $inp - UID of user whose data is being changed (may not be the currently logged in user)
	if (!$error)
	{
	  unset($_POST['password1']);
	  unset($_POST['password2']);
	  
	  
      $_POST['user_id'] = intval($inp);


	  $ret = $e_event->trigger("preuserset", $_POST);

	  if ($ret == '')
	  {
		// Either delete this block, or delete user_customtitle from the later loop for non-vetted fields
		$new_customtitle = "";
		if(isset($_POST['customtitle']) && ($pref['signup_option_customtitle'] || ADMIN))
		{
		  $new_customtitle = $tp->toDB($_POST['customtitle']);
		  if ($new_customtitle != $udata['user_customtitle']) $changed_user_data['user_customtitle'] = $new_customtitle;
		}


		// Extended fields - handle any hidden fields
		if($ue_fields)
		{
		  $hidden_fields = implode("^", array_keys($_POST['hide']));
		  if($hidden_fields != "")
		  {
			$hidden_fields = "^".$hidden_fields."^";
		  }
		  $ue_fields .= ", user_hidden_fields = '".$hidden_fields."'";
		}


		// Handle fields which are just transferred without vetting (but are subject to toDB() for exploit restriction)
		$copy_list = array('user_signature' => 'signature', 
							'user_login' => 'realname', 
							'user_email' => 'email',
							'user_hideemail' =>'hideemail',
							'user_xup' => 'user_xup');
		
		// Next list identifies numerics which might take a value of 0
		$non_text_list = array(
							'user_hideemail' =>'hideemail'
							);
		foreach ($copy_list as $k => $v)
		{
		  if (isset($_POST[$v]) && (trim($_POST[$v]) || isset($non_text_list[$k])))
		  {
		    $_POST[$v] = $tp->toDB(trim($_POST[$v]));
			if ($_POST[$v] != $udata[$k]) 
			{
			  $changed_user_data[$k] = $_POST[$v];
//			  echo "Changed {$k}, {$v} from {$udata[$k]} to {$_POST[$v]}<br />";
			}
		  }
		}


		// Update Userclass - only if its the user changing their own data (admins can do it another way)
		if (!$_uid)
		{
		  if (!is_object($e_userclass)) $e_userclass = new user_class;
		  $ucList = explode(',',$e_userclass->get_editable_classes());			// List of classes which this user can edit
		  if (count($ucList))
		  {
			if (US_DEBUG) $admin_log->e_log_event(10,debug_backtrace(),"DEBUG","Usersettings test","Read editable list. Current user classes: ".$udata['user_class'],FALSE,LOG_TO_ROLLING);

			$cur_classes = explode(",", $udata['user_class']);			// Current class membership
			$newclist = array_flip($cur_classes);						// Array keys are now the class IDs

			// Update class list - we must take care to only change those classes a user can edit themselves 
			foreach ($ucList as $cid)
			{
			  if(!in_array($cid, $_POST['class']))
			  {
				unset($newclist[$cid]);
			  }
			  else
			  {
				$newclist[$cid] = 1;
			  }
			}
			$newclist = array_keys($newclist);
			$nid = implode(',', array_diff($newclist, array('')));
//			echo "Userclass data - new: {$nid}, old: {$udata['user_class']}<br />";
			if ($nid != $udata['user_class'])
			{
			  if (US_DEBUG) $admin_log->e_log_event(10,debug_backtrace(),"DEBUG","Usersettings test","Write back classes; old list: {$udata['user_class']}; new list: ".$nid,FALSE,LOG_TO_ROLLING);
			  $changed_user_data['user_class'] = $nid;
			}
		  }
		}



		// Only admins can update login name - do this just in case one of the event triggers has mucked it about
		if (!(ADMIN && getperms("4")))
		{
		  unset($changed_user_data['user_loginname']);
		}


		// We can update the basic user record now - can just update fields from $changed_user_data
		if (US_DEBUG) $admin_log->e_log_event(10,debug_backtrace(),"DEBUG","Usersettings test","Changed data:<br> ".var_export($changed_user_data,TRUE),FALSE,LOG_TO_ROLLING);
		$sql->db_UpdateArray("user",$changed_user_data," WHERE user_id='".intval($inp)."' ");

		// Now see if we need to log anything. First check the options and class membership
		// (Normally we would leave logging decision to the log class. But this one's a bit more complicated)
		$user_logging_opts = array_flip(explode(',',varset($pref['user_audit_opts'],'')));
		$do_log = array();
		$log_action = '';
		if ($_uid)
		{		// Its an admin changing someone elses data - make an admin log entry here
		  $admin_log->log_event('USET_01',"UID: {$udata['user_id']}. UName: {$udata['user_name']}",E_LOG_INFORMATIVE);
		  // Check against the class of the target user, not the admin!
		  if (!check_class(varset($pref['user_audit_class'],''),$udata['user_class'])) $user_logging_opts = array();
		}
		else
		{
		  if (!check_class(varset($pref['user_audit_class'],''))) $user_logging_opts = array();
		}
		
		// Now log changes if required
		if (count($user_logging_opts))
		{
			// Start with any specific fields we're changing

			if (isset($changed_user_data['user_name']))
			{
			  if (isset($user_logging_opts[USER_AUDIT_NEW_DN]))
			  {
				$do_log['user_name'] = $changed_user_data['user_name'];
				$log_action = USER_AUDIT_NEW_DN;
			  }
			  unset($changed_user_data['user_name']);
			}

			if (isset($changed_user_data['user_password']))
			{
			  if (isset($user_logging_opts[USER_AUDIT_NEW_PW]))
			  {	// Password has already been changed to an md5(), so OK to leave the data
				$do_log['user_password'] = $changed_user_data['user_password'];
				$log_action = USER_AUDIT_NEW_PW;
			  }
			  unset($changed_user_data['user_password']);
			}

			if (isset($changed_user_data['user_email']))
			{
			  if (isset($user_logging_opts[USER_AUDIT_NEW_EML]))
			  {
				$do_log['user_email'] = $changed_user_data['user_email'];
				$log_action = USER_AUDIT_NEW_EML;
			  }
			  unset($changed_user_data['user_email']);
			}

			if (count($changed_user_data) && isset($user_logging_opts[USER_AUDIT_NEW_SET]))
			{
			  $do_log = array_merge($do_log,$changed_user_data);
			  $log_action = USER_AUDIT_NEW_SET;
			}
			if (count($do_log))
			{  // Got some changes to audit
//			echo "Adding to audit log<br />";
			  if ($_uid)
			  {
				$log_action = USER_AUDIT_ADMIN;						// If an admin did the mod, different heading
				// Embed a message saying who changed the data
				$changed_user_data['message'] = str_replace(array('--ID--','--LOGNAME--'),array(USERID,USERNAME),LAN_USET_18);
				$admin_log->user_audit($log_action,$do_log, $udata['user_id'],$udata['user_loginname']);
			  }
			  else
			  {
				if (count($do_log) > 1)  $log_action = USER_AUDIT_NEW_SET;		// Log multiple entries to one record
				$admin_log->user_audit($log_action,$do_log);
			  }
			}
		}	// End of audit logging

		
		// Now tidy up
		if ($photo_to_delete)
		{	// Photo may be a flat file, or in the database
		  delete_file($photo_to_delete);
		}
		if ($avatar_to_delete)
		{	// Avatar may be a flat file, or in the database
		  delete_file($avatar_to_delete);
		}


		// If user has changed display name, update the record in the online table
		if(isset($changed_user_data['user_name']) && !$_uid)
		{
		  $sql->db_Update("online", "online_user_id = '".USERID.".".$changed_user_data['user_name']."' WHERE online_user_id = '".USERID.".".USERNAME."'");
		}


		// Save extended field values
		if($ue_fields)
		{
// ***** Next line creates a record which presumably should be there anyway, so could generate an error
		  $sql->db_Select_gen("INSERT INTO #user_extended (user_extended_id, user_hidden_fields) values ('".intval($inp)."', '')");
		  $sql->db_Update("user_extended", $ue_fields." WHERE user_extended_id = '".intval($inp)."'");
		}


		// Update XUP data if file name changed.
		if(isset($changed_user_data['user_xup']))
		{
		  require_once(e_HANDLER."login.php");
		  userlogin::update_xup($inp, $changed_user_data['user_xup']);
		}


		$e_event->trigger("postuserset", $_POST);


		if(e_QUERY == "update") 
		{
          header("Location: index.php");
		}
		$message = "<div style='text-align:center'>".LAN_150."</div>";
		$caption = LAN_151;
	  } 
	  else 
	  {	// Invalid data
		$message = "<div style='text-align:center'>".$ret."</div>";
		$caption = LAN_151;
	  }
	  unset($_POST);
	}
}

if ($error)
{
	require_once(e_HANDLER."message_handler.php");
	message_handler("P_ALERT", $error);
	$adref = $_POST['adminreturn'];
}

// --- User data has been updated here if appropriate ---

if(isset($message))
{
	$ns->tablerender($caption, $message);
}


//-----------------------------------------------------
// Re-read the user data into curVal (ready for display)
//-----------------------------------------------------

$uuid = ($_uid) ? $_uid : USERID;			// If $_uid is set, its an admin changing another user's data

$qry = "
SELECT u.*, ue.* FROM #user AS u
LEFT JOIN #user_extended AS ue ON ue.user_extended_id = u.user_id
WHERE u.user_id='".intval($uuid)."'
";

$sql->db_Select_gen($qry);
$curVal=$sql->db_Fetch();
$curVal['userclass_list'] = addCommonClasses($curVal);


if($_POST)
{     // Fix for all the values being lost when there was an error in a field - restore from the latest $_POST values
	  // (Password fields have intentionally been cleared). If no error, there's an unset($_POST) to disable this block
  foreach($_POST as $key => $val)
  {
	$curVal["user_".$key] = $val;
  }
  foreach($_POST['ue'] as $key => $val)
  {
	$curVal[$key] = $val;
  }
}

require_once(e_HANDLER."form_handler.php");
$rs = new form;

$text = (e_QUERY ? $rs->form_open("post", e_SELF."?".e_QUERY, "dataform", "", " enctype='multipart/form-data'") : $rs->form_open("post", e_SELF, "dataform", "", " enctype='multipart/form-data'"));

if(e_QUERY == "update")
{
	$text .= "<div class='fborder' style='text-align:center'><br />".str_replace("*","<span style='color:red'>*</span>",LAN_USET_9)."<br />".LAN_USET_10."<br /><br /></div>";
}

$text .= $tp->parseTemplate($USERSETTINGS_EDIT, TRUE, $usersettings_shortcodes);
$text .= "<div>";

$text .= "
	<input type='hidden' name='_uid' value='{$uuid}' />
	</div>
	</form>
	";

$ns->tablerender(LAN_155, $text);
require_once(FOOTERF);


// If a field is required, returns a red asterisk
function req($field) 
{
	global $pref;
	if ($field == 2)
	{
		$ret = "<span style='text-align:right;font-size:15px; color:red'> *</span>";
	}
	else
	{
		$ret = "";
	}
	return $ret;
}



// Delete a file from the public directories. Return TRUE on success, FALSE on failure.
// Also deletes from database if appropriate.
function delete_file($fname, $dir = 'avatars/')
{
  global $sql;
  if (!$fname) return FALSE;
  
  if (preg_match("#Binary (.*?)/#", $fname, $match)) 
  {
	return $sql -> db_Delete("rbinary", "binary_id='".$tp -> toDB($match[1])."'");
  }
  elseif (file_exists(e_FILE."public/".$dir.$fname)) 
  {
	unlink(e_FILE."public/".$dir.$fname);
	return TRUE;
  }
  return FALSE;
}


function headerjs() 
{
	global $cal;
	$script = "<script type=\"text/javascript\">
		function addtext_us(sc){
		document.getElementById('dataform').image.value = sc;
		}

		</script>\n";

	$script .= $cal->load_files();
	return $script;
}
?>