# FILE: ui-prfle.pl
# DESCRIPTION: User Interface Profile Editor/Manager
#-------------------------------------------------------------------------------
# DISCUS COPYRIGHT NOTICE
#
# Discus is copyright (c) 2002 by DiscusWare, LLC, all rights reserved.
# The use of Discus is governed by the Discus License Agreement which is
# available from the Discus WWW site at:
#    http://www.discusware.com/discus/license
#
# Pursuant to the Discus License Agreement, this copyright notice may not be
# removed or altered in any way.
#-------------------------------------------------------------------------------

use strict;
use vars qw($GLOBAL_OPTIONS $PARAMS $DCONF);

###
### user_interface_profile_control
###
### Controls the "Edit Profile" aspect of the user interface as well as the
### appropriate related items when editing one's profile through Administration
###

sub user_interface_profile_control {
	my $FORMref = parse_form($ENV{'QUERY_STRING'}, $ENV{'CONTENT_LENGTH'});
	dreq("template", "authpass");
	uiprfle_login($FORMref) if ! $FORMref->{action};
	uiprfle_logout($FORMref) if $FORMref->{action} eq "logout";
	if ($FORMref->{action} =~ m%^(edit|del)post%) {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("fcn-edt-PRO");
		fcn_edt_main($FORMref);
	}
	if ($FORMref->{action} =~ m%^rate%) {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("fcn-vote-PRO");
		fcn_vote_main($FORMref);
	}
	if ($FORMref->{action} =~ m|^register|) {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("selfreg-PRO"); self_registration_control($FORMref);
	}
	if ($FORMref->{action} eq "pict") {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("fcn-prfl-PRO");
		enhanced_profile_picture_show($FORMref->{file}, 0);
	}
	if ($FORMref->{action} eq "view_profile") {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("fcn-prfl-PRO"); enhanced_profile_profile_show($FORMref->{profile}, $FORMref);
	}
	if ($FORMref->{action} eq "emsel") {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("fcn-prfl-PRO"); email_by_subtopic_select($FORMref);
	}
	if ($FORMref->{action} =~ m|^forgot|) {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("forgotpw-PRO"); forgotten_password_manager($FORMref);
	}
	if ($FORMref->{action} eq "profile_activate") {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("suspend-PRO"); suspend_activation($FORMref);
	}
	if ($FORMref->{action} =~ m|^send|) {
		error_message(read_language()->{FEATURE_NOT_SUPPORTED}, read_language()->{FEATURE_NOT_SUPPORTED_DESCR}, 0, 1) if ! $DCONF->{pro};
		dreq("pvtmsg-PRO"); private_messaging($FORMref);
	}
	if ($FORMref->{action} eq 'quick') {
		dreq("quickadm-PRO");
		quick_admin_handler($FORMref);
	}
	undef my $result;
	if ($FORMref->{username} && ! $FORMref->{password} && $FORMref->{encpass} && $GLOBAL_OPTIONS->{email_edit_profile_link}) {
		$result = check_password($FORMref->{username}, undef, undef, { cpwd => $FORMref->{encpass}, rpwd => "x" });
	} else {
		$result = check_password($FORMref->{username}, $FORMref->{password}, { nocookies => 1 }, $FORMref->{COOKIE});
	}
	error_message(read_language()->{PROFILE_AUTHERROR}, read_language()->{PROFILE_AUTHERROR_DESCR_V4}, 0, 1) if (ref $result ne "ARRAY" || scalar @{$result} == 0);
	if ($result->[0]->{database} ne "passwd" || $result->[0]->{user} ne $DCONF->{superuser}) {
		error_message(read_language()->{PROFILE_EDITING_PROHIBITED}, read_language()->{PROFILE_EDITING_EXPLANATION}, 0, 1) if $result->[0]->{edit} == 0;
	}
	uiprfle_delete_yourself($result) if $FORMref->{action} eq "delacct";
	uiprfle_save_changes($FORMref, $result) if $FORMref->{action} eq "profile_save";
	my $cookie_str = "";
	if ($DCONF->{pro}) {
		dreq("fcn-prfl-PRO");
		$result = enhance_result_profile($result);
		my $prefstr = join("", grep { length($_) == 1 } keys %{$result->[0]->{enhanced}->{pref}});
		if ($prefstr =~ /[ab]/i) {
			dreq("authwrap-PRO");
			$cookie_str .= create_user_access_cookies($FORMref, {}, $result, $prefstr);
		}
	}
	uiprfle_edit_yourself($FORMref, $result, undef, $cookie_str);
}

###
### email_notification_to_hash
###
### Converts the e-mail notification string (as stored in the file) into a hash
### of topics and/or subtopics for notification
###

sub email_notification_to_hash {
	my ($string) = @_;
	my $s = {};
	my @t = split(/,/, $string);
	foreach my $t (@t) {
		if ($t eq "0") {
			$s->{own_post} = 1;
		} elsif ($t eq "00") {
			$s->{reply_post} = 1;
		} elsif ($t eq "000") {
			$s->{format_html} = 1;
		} elsif ($t =~ m|^(\d+)/(.*)|) {
			my ($topic, $subs) = ($1, $2);
			my @u = split(/&/, $subs);
			foreach my $u (@u) {
				$s->{$topic}->{$u} = 1;
			}
		} elsif ($t =~ m|^(\d+)$|) {
			$s->{$1}->{'*'} = 1;
		}
	}
	return $s;
}

###
### email_notification_hash_to_line
###
### Converts an e-mail notification hash to a line
###

sub email_notification_hash_to_line {
	my ($hash) = @_;
	my @t = ();
	push @t, "0" if $hash->{own_post} == 1;
	push @t, "00" if $hash->{reply_post} == 1;
	push @t, "000" if $hash->{format_html} == 1;
	foreach my $t (keys(%{ $hash })) {
		next if $t !~ m|^\d+$|;
		if ($hash->{$t}->{'*'}) {
			push @t, $t;
		} else {
			push @t, join("/", $t, join("&", keys(%{ $hash->{$t} })));
		}
	}
	return join(",", @t);
}

###
### uiprfle_save_changes
###
### Saves changes to your profile
###

sub uiprfle_save_changes {
	my ($FORMref, $result) = @_;
	dreq("fcn-acct");
	my $cookie_str = "";
	my @rn = ();
	if ($DCONF->{pro}) {
		dreq("authwrap-PRO", "fcn-prfl-PRO");
		my $f = read_profile_fields();
		foreach my $ff (@{ $f }) {
			if ($ff->{require} && $ff->{descr} ne "") {
				my $k = join("", "field", $ff->{var}, "_value");
				if ($FORMref->{$k} !~ m|\S|) {
					my $l = read_language()->{PROFILE_NOT_FILLED_IN_REQUIRED};
					$l =~ s/\\n//g;
					$l =~ s/\%fieldname/$ff->{descr}/g;
					error_message(read_language()->{PROFEDIT_TITLE}, $l, 0, 1);
				}
			}
		}
		enhanced_profile_update($FORMref, $result);
#		my ($ckstr, $frcook) = uiprfle_logout($FORMref, 1);
#		$cookie_str .= $ckstr;
#		$FORMref->{COOKIE} = $frcook;
		my $cache = acs_update_account_info(undef, $result, $FORMref);
		my $ckstr2 = create_user_access_cookies($FORMref, $cache, $result);
		$cookie_str .= $ckstr2;
	}
	my @rs = @{ $result };
	my $is_mod = 0;
	$is_mod = 1 if grep { $_->{database} eq "passwd" } @rs;
	foreach my $r (@rs) {
		my $s = {};
		$s->{user} = $r->{user};
		$s->{fullname} = $GLOBAL_OPTIONS->{name_length_limit} ? substr($FORMref->{fullname}, 0, $GLOBAL_OPTIONS->{name_length_limit_number}) : $FORMref->{fullname};
		if (($GLOBAL_OPTIONS->{pwchange} || $is_mod) && $FORMref->{new_pass_1} ne "") {
			my ($pw1, $pw2) = prepare_userpass_p($FORMref->{new_pass_1}, $FORMref->{new_pass_2});
			if ($pw1 ne $pw2 || length($pw1) < 1) {
				error_message(read_language()->{PROFILE_CHPASS_ERROR}, read_language()->{PROFILE_CHPASS_ERROR_MATCH});
			}
			$s->{new_password} = $pw1;
			$FORMref->{password} = $pw1;
		}
		if (! $DCONF->{pro} || $GLOBAL_OPTIONS->{emchange} == 1 || $r->{database} eq "passwd") {
			$s->{email} = $FORMref->{email};
		} elsif ($DCONF->{pro} && $FORMref->{email} ne $r->{email} && $GLOBAL_OPTIONS->{emchange} == 2) {
			my ($act_key, $force_pass) = email_change_effect($FORMref->{password}, $FORMref->{email}, $r->{pass}, $s->{new_password}, $r->{user});
			$s->{force_pass} = $force_pass;
			$s->{email} = $FORMref->{email};
			$FORMref->{activ8} = 1;
		} elsif ($DCONF->{pro} && $FORMref->{force_resend_key}) {
			my ($act_key, $force_pass) = email_change_effect($FORMref->{password}, $r->{email}, $r->{pass}, $s->{new_password}, $r->{user});
			$s->{force_pass} = $force_pass;
			$FORMref->{activ8} = 1;
		} elsif ($DCONF->{pro} && $FORMref->{email_activation}) {
			my $force_pass = email_change_activate($r->{pass}, $s->{new_password}, $FORMref->{email_activation});
			$s->{force_pass} = $force_pass;
		} else {
			$s->{email} = $r->{email};
		}
		if ($FORMref->{email_included} == 1) {
			my $h = {}; my $rr = {};
			my @r = split(/,/, $FORMref->{bysub});
			foreach my $_r (@r) {
				if ($_r =~ m|^(\d+):(.*)|) {
					my ($topic, $splits) = ($1, $2);
					my @sp = split(/&/, $splits);
					foreach my $sp (@sp) {
						$rr->{$topic}->{$sp} = 1;
					}
				}
			}
			my @s = split(/,/, $FORMref->{notify});
			foreach my $s (@s) {
				if ($s =~ m|^0+$|) {
					$h->{own_post} = 1 if $s eq "0";
					$h->{reply_post} = 1 if $s eq "00";
					$h->{format_html} = 1 if $s eq "000";
				} elsif (defined $rr->{$s}) {
					$h->{$s} = $rr->{$s};
				} else {
					$h->{$s}->{'*'} = 1 if ! defined $rr->{$s};
				}
			}
			if ($DCONF->{pro}) {
				dreq("fcn-prfl-PRO");
				($h, $cookie_str) = notification_simple_prune($h, $FORMref, undef, $result);
			}
			$s->{notify} = email_notification_hash_to_line($h);
		}
		if ($r->{database} eq "passwd" && $r->{user} eq $DCONF->{superuser} && defined $FORMref->{cmonth}) {
			my $k = eval '
				use Time::Local;
				my $x = timelocal(0,0,12,$FORMref->{cday},$FORMref->{cmonth},$FORMref->{cyear});
				$x;
			';
			if ($@ eq "" && $k > 0) {
				$s->{ctime} = $k;
			}
		}
		my ($success, $failure) = update_account($s, $r->{database}, undef);
		my $Z = \%{$r}; $Z = hash_merge($Z, $s, 1);
		push @rn, $Z;
		$r = $success->[0] if ref $success eq "ARRAY" && ref $success->[0] eq "HASH";
		if (ref $r eq "HASH" && $r->{database} eq "passwd" && $FORMref->{new_pass_1} ne "") {
			$cookie_str .= cookie_string_format("pass", crypt($r->{pass}, "cookie"));
		}
		if ($DCONF->{pro} && ref $r eq "HASH") {
			dreq("fcn-prfl-PRO", "authwrap-PRO");
			my $l = enhance_result_profile($r);
			my $prefstr = join("", grep { length($_) == 1 } keys %{$l->[0]->{enhanced}->{pref}});
			if ($prefstr =~ /[ab]/i) {
				dreq("authwrap-PRO");
				$cookie_str .= create_user_access_cookies($FORMref, {}, [$Z], $prefstr);
			} elsif ($prefstr !~ /[ab]/i && $FORMref->{COOKIE}->{user} ne "") {
				$cookie_str .= uiprfle_logout($FORMref, 3);
			}
		}
	}
	uiprfle_edit_yourself($FORMref, \@rn, { saved => 1 }, $cookie_str);
}

###
### uiprfle_delete_yourself
###
### Handles deleting of your own profile (i.e., commit suicide)
###

sub uiprfle_delete_yourself {
	my ($result) = @_;
	error_message("Permission Denied", "You cannot delete your own account on this board.", 0, 1) if ! $GLOBAL_OPTIONS->{user_selfdel};
	foreach my $r (@{ $result }) {
		error_message("Permission Denied", "The superuser account cannot be deleted.", 0, 1) if $r->{user} eq $DCONF->{superuser} && $r->{database} eq "passwd";
	}
	dreq("fcn-acct");
	dreq("fcn-prfl-PRO") if $DCONF->{pro};
	my $succ_total = 0;
	foreach my $r (@{ $result }) {
		my ($success, $failure) = delete_account({$r->{user} => 1}, undef, $r->{database});
		$succ_total += 1 if $success;
		if ($DCONF->{pro}) {
			delete_enhanced_profile_record({$r->{user} => 1}, $r->{database});
		}
	}
	if ($succ_total == scalar(@{ $result })) {
		screen_out("acctdel", {}, undef);
	} else {
		error_message(read_language()->{PROFILE_DELETE_FAILED}, read_language()->{PROFILE_DELETE_FAILED_EXPLANATION}, 0, 1);
	}
}

###
### profile_editor_email_notification_freeware
###
### Sets up Discus freeware e-mail notification fields
###

sub profile_editor_email_notification_freeware {
	my ($subst, $FORMref, $cookie_str, $current, $h) = @_;
	my $notify = email_notification_to_hash($h->{notify});
	my $topic_list = board_topics();
	my @f2 = ();
	foreach my $topic (@{ $topic_list }) {
		next if $topic->{type} != 1;
		my $sel = 0;
		$sel = 1 if defined $notify->{$topic->{number}};
		push @f2, { number => $topic->{number}, name => $topic->{name}, sel => $sel };
	}
	$subst->{notify_topics} = \@f2;
	$subst->{notify} = $notify;
	return ($subst, $cookie_str);
}

###
### uiprfle_edit_yourself
###
### Allows you to edit your own profile
###

sub uiprfle_edit_yourself {
	my ($FORMref, $result, $stuff, $cookie_str) = @_;
	maintenance_mode_error() if ($GLOBAL_OPTIONS->{maintenance} && ($result->[0]->{user} ne $DCONF->{superuser} || $result->[0]->{database} ne "passwd"));
	my $subst = {};
	my $in_cookie_str = "";
	my $current = undef;
	my $h = $result->[0];
	$subst->{general}->{account_type} = $result->[0]->{database} eq "passwd" ? "moderator" : "user";
	$subst->{general}->{allow_edit_posts} = 1;
	$subst->{general}->{allow_delete_posts} = 1;
	$subst->{general}->{changed_email} = $h->{changed_email};
	$subst->{general}->{spell_checking_enabled} = (-e "$DCONF->{admin_dir}/msg_index/wordlist.txt") * $GLOBAL_OPTIONS->{spell_check};
	if ($FORMref->{activ8}) {
		$subst->{general}->{username} = $h->{user};
		$subst->{general}->{password} = $FORMref->{password};
		screen_out("chgd_eml", $subst);
	}
	$subst->{stuff} = $stuff;
	my @m = ();
	$subst->{messages} = \@m;
	if ($DCONF->{pro}) {
		dreq("fcn-prfl-PRO", "authwrap-PRO");
		($subst, $in_cookie_str) = profile_editor_variables($subst, $FORMref, $cookie_str, $current, $h, $result);
	} else {
		($subst, $in_cookie_str) = profile_editor_email_notification_freeware($subst, $FORMref, $cookie_str, $current, $h);
	}
	$cookie_str .= $in_cookie_str;
	my @l = localtime($h->{ctime} + $GLOBAL_OPTIONS->{'timezone'}*3600);
	$subst->{creation}->{month} = $l[4];
	$subst->{creation}->{day} = $l[3];
	$subst->{creation}->{year} = 1900 + $l[5];
	$subst->{creation}->{curryear} = 1900 + (localtime(time))[5];
	$subst->{general}->{groups} = $result->[0]->{groups};
	my @grps = map { { group => $_ } } grep { /\S/ } split(/\//, $result->[0]->{groups});
	$subst->{groups} = \@grps;
	$subst->{general}->{editing} = 0;
	$subst->{general}->{username} = $h->{user};
	$subst->{general}->{password} = $FORMref->{password};
	$subst->{general}->{encpass} = $FORMref->{encpass};
	$subst->{general}->{action} = "profile_save";
	$subst->{general}->{action_url} = join("/", $DCONF->{script_url}, "board-profile.$DCONF->{cgi_extension}");
	$subst->{general}->{is_superuser} = 1 if $h->{database} eq "passwd" && $h->{user} eq $DCONF->{superuser};
	$subst->{ffield}->{fullname} = $h->{fullname};
	$subst->{ffield}->{email} = $h->{email};
	$subst->{general}->{email_notification} = 0;
	if ($GLOBAL_OPTIONS->{email}) {
		if ($GLOBAL_OPTIONS->{send_mail_only_admins} == 0) {
			$subst->{general}->{email_notification} = 1;
		} else {
			foreach my $r (@{ $result }) {
				$subst->{general}->{email_notification} = 1 if $r->{database} eq "passwd";
			}
		}
	}
	if ($GLOBAL_OPTIONS->{emchange} == 0 && $DCONF->{pro}) {
		$subst->{general}->{prevent_change_email} = 1 if $h->{database} eq "users";
	}
	$subst->{general}->{adminprog} = 1 if $FORMref->{adminprog} == 1;
	screen_out("profile", $subst, $cookie_str);
}


###
### uiprfle_logout
###
### Clears cookies to log someone out
###

sub uiprfle_logout {
	my ($FORMref, $cancel) = @_;
	my $cookie_out = "";
	my %formrefcookie = %{ $FORMref->{COOKIE} };
	foreach my $cookie (keys(%{$FORMref->{COOKIE}})) {
		next if $cookie =~ m%^(lastvisit|offset|lastsession)$%;
		next if $cookie =~ m%^(uid|admuser|pass)$% && $cancel == 3;
		$cookie_out .= cookie_string_format($cookie, "undef", "Wednesday, 16-Aug-2000 00:00:00 GMT");
		$formrefcookie{$cookie} = undef;
	}
	return ($cookie_out, \%formrefcookie) if $cancel == 1;
	if ($FORMref->{COOKIE}->{uid} && $DCONF->{pro}) {
		dreq("authwrap-PRO");
		acs_delete_token($FORMref->{COOKIE}->{uid});
	}
	return $cookie_out if $cancel >= 2;
	$FORMref->{COOKIE} = \%formrefcookie;
	dreq("ui-main");
	user_interface_main_control($FORMref, $cookie_out);
}

###
### uiprfle_login
###
### Presents the traditional "Log In" screen for the profile editor
###

sub uiprfle_login {
	my ($FORMref, $messagecode, $arg) = @_;
	my $subst = {};
	$subst->{fill}->{user} = (defined $FORMref->{COOKIE}->{"user$DCONF->{COOKIE_ID}"} ? $FORMref->{COOKIE}->{"user$DCONF->{COOKIE_ID}"} : (defined $FORMref->{COOKIE}->{"admuser$DCONF->{COOKIE_ID}"} ? $FORMref->{COOKIE}->{"admuser$DCONF->{COOKIE_ID}"} : ""));
	foreach my $c (keys(%{ $FORMref->{COOKIE} })) {
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^user|;
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^cpwd|;
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^rpwd|;
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^pass|;
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^admuser|;
		$subst->{fill}->{is_logged_in} = 1 if $c =~ m|^uid|;
	}
	$subst->{general}->{messagecode} = $messagecode->{code};
	$subst->{editor} = $messagecode;
	$subst->{arg} = $arg;
	$subst->{general}->{authentication_error} = defined $messagecode->{autherr} ? 0 + $messagecode->{autherr} : $FORMref->{username} ne "" || $FORMref->{password} ne "" ? 1 : 0;
	screen_out("usrlogin", $subst);
}



1;
