# FILE: adm-opts.pl
# DESCRIPTION: Options 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 $DCONF $PARAMS);

###
### OPTS_admin
###
### Runs the Options Manager
###

sub OPTS_admin {
	my ($FORMref) = @_;
	my $result = check_password($FORMref->{username}, undef, { type_required => 'moderator' }, $FORMref->{'COOKIE'});
	bad_login( { bad_username => 1 } ) if scalar(@{ $result }) == 0;
	bad_login( { superuser_required => 1 } ) if $result->[0]->{user} ne $DCONF->{superuser};
	options_mgr($FORMref, $result) if $FORMref->{action} eq "options_mgr";
	options_mailconfig($FORMref, $result) if $FORMref->{c} eq "mail_config";
	options_formsave($FORMref, $result) if $FORMref->{action} eq "options_save";
	options_profanity($FORMref, $result) if $FORMref->{action} eq "options_profanity";
	options_domains($FORMref, $result) if $FORMref->{action} eq "options_domains";
	options_private_log($FORMref, $result) if $FORMref->{action} eq "options_private_log";
	options_email_defaults($FORMref, $result) if $FORMref->{action} eq "options_email_default";
	options_mailpop($FORMref, $result) if $FORMref->{action} eq "options_email_cfg";
	options_mail_save($FORMref, $result) if $FORMref->{action} eq "options_mail_save";
	options_speller($FORMref, $result) if $FORMref->{action} =~ m|^options_mgr_sd(\d)$|;
}

###
### options_mail_save
###
### Save or test e-mail notification settings
###

sub options_mail_save {
	my ($FORMref, $result) = @_;
	dreq("mailer");
	my $j = readfile("$DCONF->{admin_dir}/email.txt", "options_mail_save", { create => 1, zero_ok => 1, no_lock => 1, no_unlock => 1 });
	my $Q = email_configuration_read($j);
	if ($Q->{no_use} != 1) {
		foreach my $d ('to', 'from', 'subject', 'replyto', 'bcc', 'user') {
			my $D = join("", $d, "address");
			$Q->{$D} = $FORMref->{$D};
			$Q->{join("_", $D, 'prefix')} = $FORMref->{join("_", $D, 'prefix')};
		}
		foreach my $d ('lineformat', 'tempfile', 'test_email_address', '1message', 'mail_program', 'commandline', 'commandlineend', 'net_SMTP', 'SMTP', 'SMTP2', 'SMTP3') {
			$Q->{$d} = $FORMref->{$d};
		}
		($Q->{command_line}, $Q->{input_stream}) = construct_command_line_string($Q);
	}
	if ($FORMref->{no_test} == 1) {
		if ($Q->{no_use} != 1) {
			email_configuration_save($Q, undef);
			options_mailpop($FORMref, $result, { saved => 1 });
		} else {
			options_mailpop($FORMref, $result, {});
		}
	}
	if ($FORMref->{test_email_address} =~ /^([\w\+\-\.]+)\@([\w\+\-\.]+)$/) {
		my $o; my $F;
		if ($Q->{no_use} != 1) {
			$o = email_configuration_save($Q, $j);
			$F = email_configuration_read($o);
		} else {
			$F = $Q;
		}
		my $sh = { to => $FORMref->{test_email_address}, subject => read_language()->{EMAIL_NOTIFICATION_TEST_SUBJECT} };
		my $mm = {};
		my @var = map { name => $_, setting => $F->{$_} }, keys(%{$F});
		$mm->{var} = \@var;
		$mm->{general}->{username} = $result->[0]->{user};
		$mm->{general}->{pwstring} = crypt($result->[0]->{pass}, "cookie");
		$mm->{general}->{reply_disabled} = 1 if $F->{'1message'} == 1;
		my $txt = templ_int("testmail", $mm);
		send_email_message($sh, $txt, $F, 1);
		my $subst = {};
		$subst->{mail} = $F;
		$subst->{mail} = $subst->{guess} if ! defined $subst->{mail}->{net_SMTP};
		$subst = options_email_config($subst, $o);
		$subst->{general}->{username} = $result->[0]->{user};
		$subst->{general}->{cron_available} = (-e "$DCONF->{admin_dir}/mailqueue" ? 1 : 0 );
		$subst->{general}->{sent} = 1;
		screen_out("mailpop", $subst);	
	} else {
		error_message("Invalid Test Address", "The e-mail address you entered to send the test to is not valid.", 0, 1);
	}
}

###
### options_email_defaults
###
### Defaults for e-mail notification
###

sub options_email_defaults {
	my ($FORMref, $result) = @_;
	my $subst = {};
	my $q = board_topics(undef, undef, undef, 1);
	dreq("ui-prfle");
	if ($DCONF->{pro} && $GLOBAL_OPTIONS->{email_bysubtopic}) {
		dreq("fcn-prfl-PRO");	
		$subst = (profile_editor_email_notification_pro($subst, $FORMref, "", "", undef, $q, $GLOBAL_OPTIONS->{default_notify_string}))[0];
	} else {
		my @q = @{$q};
		my @f2 = ();
		my $notify = email_notification_to_hash($GLOBAL_OPTIONS->{default_notify_string});
		foreach my $topic (@q) {
			next if $topic->{type} != 1;
			my $sel = 0;
			$sel = 2 if defined $notify->{$topic->{number}};
			$sel = 1 if defined $notify->{$topic->{number}}->{'*'};
			push @f2, { number => $topic->{number}, name => $topic->{name}, sel => $sel };
		}
		$subst->{notify} = $notify;
		$subst->{notify_topics} = \@f2;
	}
	$subst->{general}->{username} = $result->[0]->{user};
	screen_out("em_def", $subst);	
}

###
### options_domains
###
### Banned domains for user self-registration
###

sub options_domains {
	my ($FORMref, $result) = @_;
	dreq("selfreg-PRO"); options_domains_pro($FORMref, $result);
}

###
### options_private_log
###
### View private messaging log
###

sub options_private_log {
	my ($FORMref, $result) = @_;
	dreq("pvtmsg-PRO"); options_private_log_pro($FORMref, $result);
}
	

###
### options_profanity
###
### Configuration and testing of profanity filter
###

sub options_profanity {
	my ($FORMref, $result) = @_;
	my $subst = {};
	$subst->{general}->{username} = $result->[0]->{user};
	$subst->{general}->{screen} = 0 + $FORMref->{screen};
	if ($FORMref->{changed} == 2) {
		dreq("profane");
		my $z = profanity_filter($FORMref->{testword}, { force_read => 1, force_check => 1, error_report => 3 });
		if ($z ne "") {
			my @z = ($z);
			$subst->{general}->{match} = cuss_convert_perlregexp_to_discusregexp(\@z)->[0]->{word};
		}
		$subst->{general}->{screen} = 1;
		$subst->{general}->{entry} = $FORMref->{testword};
	} else {
		my $cuss = undef;
		if ($FORMref->{words}) {
			$cuss = cuss_save($FORMref->{words});
		} else {
			dreq("profane");
			$cuss = read_cuss_file(1);
		}
		$subst->{words} = cuss_convert_perlregexp_to_discusregexp($cuss);
	}
	$subst->{checkup} = options_profanity_scanner();
	screen_out("cussedit", $subst, undef);
}

###
### options_profanity_scanner
###
### Sees if your word list is too redundant
###

sub options_profanity_scanner {
	dreq("profane");
	my $cussfile = ref $_[0] eq 'ARRAY' ? $_[0] : read_cuss_file(1);
	my %l = map { $_, 1 } @{$cussfile};
	my $l = \%l;
	my $dup = {};
	my $cby = {};
	foreach my $word (@{$cussfile}) {
		next if $word !~ /\S/;
		my @x = grep { $_ ne $word } @{$cussfile};
		$dup->{$word} = 1 if scalar (grep { $_ ne $word } @x) != scalar @{$cussfile} - 1;
		my $cuss = {};
		@x = map { my $j = $_; s%\(\S\*\)%MNBVCXZ%g; s%\(\\S\)%\^%g; s%\(\\S\+\)%ZXCVBNM%g; { orig => $j, now => $_ }} @x;
		foreach my $x (@x) {
			my $wd = $word;
			eval "'foo' =~ /^$wd$/i";
			$wd = quotemeta($word) if $@;			
			$cuss->{cuss_found}->{$x->{orig}} = 1 if $x->{now} =~ /^$wd$/i;
		}
		next if scalar keys %{$cuss->{cuss_found}} == 0;
		my %z = map { $_, 1 } grep { $_ ne $word } keys %{$cuss->{cuss_found}};
		$cby->{$word} = \%z;
	}
	my $i = {};
	my @dup = sort { lc($a->{word}) cmp lc($b->{word}) } map { cuss_convert_perlregexp_to_discusregexp([$_])->[0] } keys %{$dup};
	$i->{duplicate} = \@dup;
	my @cby = sort { lc($a->{word}) cmp lc($b->{word}) } map { cuss_convert_perlregexp_to_discusregexp([$_])->[0] } keys %{$cby};
	$i->{caughtby} = \@cby;
	my $l2 = {};
	foreach my $k (keys %{$cby}) {
		foreach my $z (keys %{$cby->{$k}}) {
			$l2->{$z} = 1;
		}
	}
	$i->{duplicate_keys} = scalar keys %{$dup};
	$i->{caughtby_keys} = scalar keys %{$cby};
	my @cby2 = sort { lc($a->{word}) cmp lc($b->{word}) } map { cuss_convert_perlregexp_to_discusregexp([$_])->[0] } keys %{$l2};
	$i->{caughtby_2} = \@cby2;
	return $i;
}

###
### cuss_save
###
### Converts actual Discus regular expressions to Perl regular expressions
### for display, and saves the results
###

sub cuss_save {
	my ($input) = @_;
	$input =~ s/\r/\n/g;
	my @i = split(/\n/, $input);
	my @z = ();
	foreach my $j (@i) {
		next if $j !~ /\S/;
		my $z = quotemeta(trim($j));
		$z =~ s/\\\?/\(\\S\)/g;
		$z =~ s/\\\*/\(\\S\*\)/g;
		$z =~ s/\\\+/\(\\S\+\)/g;
		push @z, $z;
	}
	writefile("$DCONF->{admin_dir}/cuss.txt", \@z, "naughty_words", { zero_ok => 1, no_lock => 1, no_unlock => 1 });
	$PARAMS->{'naughty_words'} = \@z;
	return \@z;
}

###
### cuss_convert_perlregexp_to_discusregexp
###
### Converts actual Perl regular expressions to Discus regular expressions
### for display
###

sub cuss_convert_perlregexp_to_discusregexp {
	my ($list) = @_;
	my @z = ();
	foreach my $word (@{ $list }) {
		my $z = $word;
		$z =~ s/\(\\S\*\)/\*/g;
		$z =~ s/\(\\S\)/\?/g;
		$z =~ s/\(\\S\+\)/\+/g;
		$z =~ s/\\//g;
		push @z, { word => $z };
	}
	return \@z;
}

###
### options_mailconfig
###
### Configuration for e-mail notification, form saving
###

sub options_mailconfig {
	my ($FORMref, $result) = @_;
	my $s = {};
	my @av = ("fromaddr", "fromname", "chuckaddress");
	foreach my $x (@av) {
		$s->{$x} = $FORMref->{$x};
	}
	dreq("mailer");
	email_configuration_save($s, undef);	
}


###
### options_speller
###
### Configures the spell checker
###

sub options_speller {
	my ($FORMref, $result) = @_;
	dreq("speller-PRO");
	speller_config($FORMref, $result);
}

###
### options_formsave
###
### Saves options that were found on the form
###

sub options_formsave {
	my ($FORMref, $result) = @_;
	my $n = {};
	foreach my $u (split(/,/, $FORMref->{a})) {
		$n->{$u} = $FORMref->{$u} != 0 ? $FORMref->{$u} : 0;
	}
	foreach my $u (split(/,/, $FORMref->{b})) {
		$n->{$u} = defined $FORMref->{$u} ? $FORMref->{$u} : "";
	}
	foreach my $u (split(/,/, $FORMref->{c})) {
		$n->{$u} = options_c_saver($u, $FORMref);		
	}
	if ($FORMref->{d}) {
		dreq("webtags");
		foreach my $u (split(/,/, $FORMref->{d})) {
			if ($FORMref->{$u} !~ /\S/) {
				$n->{$u} = "";
			} else {
				my ($messages, $formatted) = webtags($FORMref->{$u}, 1, 1, 1, 1);
				if ($messages eq "!Error") {
					error_message(read_language()->{FORMATTINGERROR}, $formatted, 0, 1);
				}
				$n->{$u} = $formatted;
			}
		}
	}
	if ($FORMref->{e}) {
		dreq("ipaddr-PRO");
		options_mgr_save_ip_bans($FORMref);
	}
	if ($FORMref->{f}) {
		dreq("mailer");
		my $j = readfile("$DCONF->{admin_dir}/email.txt", "options_formsave", { create => 1, zero_ok => 1, no_lock => 1, no_unlock => 1 });
		my $Q = email_configuration_read($j);
		($Q->{command_line}, $Q->{input_stream}) = construct_command_line_string($Q);
		email_configuration_save($Q, undef);
	}
	$GLOBAL_OPTIONS = options_save($n);
	if ($DCONF->{pro} && $FORMref->{menu} == 4) {
		dreq("authwrap-PRO");
		put_topics_file_in_correct_place();
	}
	options_mgr($FORMref, $result, { saved => 1 });
}

###
### options_c_saver
###
### Special saving algorithms
###

sub options_c_saver {
	my ($option, $FORMref) = @_;
	if ($option eq "default_notify_string") {
		my $k = $FORMref->{default_notify_string};
		my @k = split(/,/, $k);
		my @l = ();
		foreach my $z (@k) {
			if ($z =~ /^(\d+):$/) {
				push @l, $1;
			} else {
				$z =~ s/:/\//g;
				push @l, $z;
			}
		}		
		return join(",", @l);
	}
	if ($option eq "fields_display") {
		my $k = $FORMref->{fields_display};
		$k =~ s/,/\//g;
		$k = "/$k/";
		return $k;
	}
	if ($option eq "mod_session_expire") {
		my $k = $FORMref->{u_last_access_info};
		return $GLOBAL_OPTIONS->{mod_session_expire} if $k == 0;
		return 0;
	}
	if ($option eq "allusers_dispfield") {
		my $k = $FORMref->{allusers_dispfield};
		$k =~ s/,/\//g;
		$k = "/$k/";
		return $k;
	}
	if ($option eq "debug_users") {
		my $k = $FORMref->{debug_users};
		my @u = split(/,/, $k);
		dreq("authpass");
		foreach my $u (@u) { $u = prepare_userpass($u); }
		@u = sort grep (/\S/, @u);
		return join(",", @u);		
	}	
	if ($option eq "default_prefs") {
		return "" if ! defined $FORMref->{pref};
		my $k = $FORMref->{pref};
		$k =~ s/\W//g;
		return $k;
	}	
	if ($option eq "permanent_prefs") {
		return "" if ! defined $FORMref->{permpref};
		my $k = $FORMref->{permpref};
		$k =~ s/\W//g;
		return $k;
	}	
	if ($option eq "profile_fields") {
		my $f = {};
		foreach my $key (keys(%{ $FORMref })) {
			next if $key eq "require_valid_email";
			$f->{$1}->{display} = $FORMref->{$key} if $key =~ m|^show_(\w+)$|;
			$f->{$1}->{require} = $FORMref->{$key} if $key =~ m|^require_(\w+)$|;
			$f->{$1}->{order} = $FORMref->{$key} if $key =~ m|^order_(\w+)$|;
			$f->{$1}->{type} = $FORMref->{$key} if $key =~ m|^type_(\w+)$|;
			$f->{$1}->{size} = $FORMref->{$key} if $key =~ m|^rows_(\w+)$|;
			$f->{$1}->{descr} = $FORMref->{$key} if $key =~ m|^descr_(\w+)$|;
		}
		my $max = 0;
		if ($f->{new}->{descr} ne "") {
			foreach my $key (keys(%{ $f })) {
				$max = $key if $key > $max;
			}
			if ($max == 20) {
				for (my $i = 20; $i >= 1; $i--) {
					if ($f->{$i}->{descr} eq "") {
						$max = $i;
						last;
					}
				}
			} else {
				$max++;
			}
		}
		my $q = {};
		my $ctr = 0;
		my @f = sort { $f->{$a}->{order} <=> $f->{$b}->{order} } keys(%{ $f });
		foreach my $ff (@f) {
			next if $ff eq "new" && $max == 0;
			my $j = $ff ne "new" ? $ff : $max;
			$q->{$j} = $f->{$ff};
			$ctr++;
			$q->{$j}->{order} = $ctr;			
		}
		my @k = ();
		foreach my $key (sort { $a <=> $b } keys(%{ $q })) {
			my $fk = $q->{$key};
			my $l = join(":", $key, $fk->{descr}, $fk->{display}, $fk->{type}, $fk->{size}, $fk->{require}, $fk->{order});
			push @k, "$l\n";			
		}
		my $filename = "$DCONF->{admin_dir}/data/fields.txt";
		writefile($filename, \@k, "options_c_saver", { no_lock => 1, no_unlock => 1, zero_ok => 1 });		
	}
	return $FORMref->{$option};	
}


###
### options_mailpop
###
### Pop-up technical configuration of e-mail program
###

sub options_mailpop {
	my ($FORMref, $result, $stuff) = @_;
	dreq("mailer");
	my $subst = {};
	$subst->{general}->{username} = $result->[0]->{user};
	$subst->{stuff} = $stuff;
	$subst->{guess} = email_guess_settings();
	$subst->{general}->{cron_available} = (-e "$DCONF->{admin_dir}/mailqueue" ? 1 : 0 );
	$subst->{mail} = email_configuration_read();
	$subst->{general}->{write_unavailable} = 0 + $subst->{mail}->{no_use};
	$subst->{mail} = $subst->{guess} if ! defined $subst->{mail}->{net_SMTP};
	$subst = options_email_config($subst);
	screen_out("mailpop", $subst);
}

###
### options_mgr
###
### Displays the Options Manager
###

sub options_mgr {
	my ($FORMref, $result, $stuff) = @_;
	my $subst = {};
	$subst->{general}->{username} = $result->[0]->{user};
	$subst->{general}->{menu} = $FORMref->{menu};
	$subst->{general}->{server_time} = time;
	$subst->{stuff} = $stuff;
	$subst->{general}->{url} = "$PARAMS->{cgiurl}?action=options_mgr&username=$FORMref->{username}";
	$subst->{topics} = board_topics(undef, undef, undef, 1, 1);
	foreach my $setting ('active_subs', 'active_subs_parents', 'reverse_subs', 'alphabet_subs', 'reverse_msgs') {
		map $subst->{$setting}->{$_} = 1, split(/,/, $GLOBAL_OPTIONS->{$setting});
	}
	if ($DCONF->{pro}) {
		dreq("bannedip-PRO");
		$subst->{ipban} = read_ip_ban_file();
		if (-e "$DCONF->{admin_dir}/msg_index/wordlist.txt") {
			$subst->{general}->{dictionary_ready} = 1;
			my $j = readfile("$DCONF->{admin_dir}/msg_index/wordlist.txt", "options_mgr", {no_lock => 1, no_unlock => 1, zero_ok => 1});
			$subst->{general}->{spelling_words} = scalar(@{ $j });
		} else {
			$subst->{general}->{dictionary_ready} = 0;
		}
		dreq("fcn-prfl-PRO");
		my @x = sort { $a->{order} <=> $b->{order} } @{ read_profile_fields() };
		$subst->{fields} = \@x;
		if ($FORMref->{menu} == 4 && $GLOBAL_OPTIONS->{login_message} ne "") {
			dreq("webtags");
			$subst->{special}->{login_message} = inverse_webtags($GLOBAL_OPTIONS->{login_message}, undef);
		}
		dreq("webtags");
		$subst->{special}->{welcome_message} = inverse_webtags($GLOBAL_OPTIONS->{welcome_message}, undef);
		for (my $i = 2; $i <= 10; $i++) {
			my $x = join("", "status", $i);
			$subst->{status}->{$x} = inverse_webtags($GLOBAL_OPTIONS->{$x}, undef);
		}
		dreq("fcn-grp");
		my $g = read_group_file(1);
		my @g = ();
		my $l = {};
		foreach my $_l (split(/,/, $GLOBAL_OPTIONS->{allusers_groups})) {
			$l->{$_l} = 1;
		}
		foreach my $gr (@{ $g->{group_list} }) {
			push @g, { name => $gr, selected => 0 + $l->{$gr} };
		}
		$subst->{groups} = \@g;
		$subst->{allusers_groups}->{moderators} = 0 + $l->{'*mod*'};
		$subst->{allusers_groups}->{users} = 0 + $l->{'*usr*'};
		$subst->{general}->{allusers_total} = scalar keys %{$l};
	}
	if ($GLOBAL_OPTIONS->{advanced_options} == 0 && defined $GLOBAL_OPTIONS->{registered_min_msgsize} && ! defined $GLOBAL_OPTIONS->{basic_configured_defaults}) {
		$GLOBAL_OPTIONS = options_save({ basic_configured_defaults => 1, advanced_options => 1 });		
	}
	if ($DCONF->{pro}) {
		if (defined $GLOBAL_OPTIONS->{installed_gd}) {
			$subst->{general}->{installed_gd} = 0 + $GLOBAL_OPTIONS->{installed_gd};
		} else {
			$GLOBAL_OPTIONS = options_save ({ installed_gd => 0 });
			eval '
				use GD;
				my $smallimage = new GD::Image(50, 50);
				my $x = $smallimage->jpeg();
			';
			if ($@ eq "") {
				$subst->{general}->{installed_gd} = 1;
				options_save ({ installed_gd => 1 });
			}
		}
	}
	$subst = options_email_config($subst) if $FORMref->{menu} == 6;
	$subst->{general}->{pop_email_config} = 1 if $FORMref->{popconfig} == 1; 
	if ($GLOBAL_OPTIONS->{advanced_options} == 1) {
		if (-e "$DCONF->{admin_dir}/data/dtaskman.pid") {
			my $pidf = readfile("$DCONF->{admin_dir}/data/dtaskman.pid", "options_mgr", { no_lock => 1, no_unlock => 1 });
			my $pid = $pidf->[0]; chomp $pid;
			if (kill(0, $pid) || $! == 1) {
				$subst->{general}->{taskman} = $pid;  ## Running
			}
		}
		my @u = map { user => $_ }, split(/,/, $GLOBAL_OPTIONS->{debug_users});
		$subst->{debug_users} = \@u;	
		screen_out("options", $subst);
	} else {
		screen_out("optionsb", $subst);
	}
}

###
### options_email_config
###
### Gets the current e-mail configuration by reading email.txt
###

sub options_email_config {
	my ($subst, $L) = @_;
	dreq("mailer");
	my $email = email_configuration_read($L);
	$subst->{general}->{net_SMTP} = $email->{net_SMTP};
	$subst->{general}->{mail_program} = $email->{mail_program};
	$subst->{general}->{SMTP} = $email->{SMTP};
	$subst->{general}->{SMTP2} = $email->{SMTP2};
	$subst->{general}->{SMTP3} = $email->{SMTP3};
	$subst->{general}->{test_email_addr} = $email->{test_email_addr};
	$subst->{mailer}->{chuckaddress} = $email->{chuckaddress};
	$subst->{mailer}->{fromname} = $email->{fromname};
	$subst->{mailer}->{fromaddr} = $email->{fromaddr};
	eval 'use Net::SMTP;';
	$subst->{mailer}->{net_smtp} = 1 if $@ eq "";
	eval 'use Mail::Sendmail;';
	$subst->{mailer}->{mail_sendmail} = 1 if $@ eq "";
	$subst->{mailer}->{raw_socket} = -1;
	eval 'use FileHandle;';
	$subst->{mailer}->{raw_socket} += 1 if $@ eq "";
	eval 'use Socket;';
	$subst->{mailer}->{raw_socket} += 1 if $@ eq "";
	$subst->{mailer}->{raw_socket} = 0 if $subst->{mailer}->{raw_socket} != 1;
	eval 'use Net::POP3;';
	$subst->{mailer}->{pop3} = 1 if $@ eq "";
	return $subst;
}

###
### options_save
###
### Writes the options.txt file with new incoming options
###

sub options_save {
	my ($new_options) = @_;
	my $options_file = readfile("$DCONF->{admin_dir}/options.txt", "options_save", { zero_ok => 1, no_unlock => 1 });
	undef my $seen;
	foreach my $line (@{ $options_file }) {
		my ($field, $value) = split(/=/, $line, 2);
		my $field2 = $field;
		$field2 =~ tr/a-zA-Z/b-zaB-Za/ if $new_options->{TRANSLATE_NAME};
		if ($field =~ /^ip_(banned|comment)_\d/ && $GLOBAL_OPTIONS->{$field2} eq "" && $new_options->{$field2} eq "") {
			$line = "";
			next;
		}
		$seen->{$field} = 1;
		$line = join("=", $field, join("", escape($new_options->{$field2}), "\n")) if defined $new_options->{$field2};
	}
	foreach my $x (keys(%{ $new_options })) {
		next if $x eq "TRANSLATE_NAME";
		my $y = $x;
		$y =~ tr/b-zaB-ZA/a-zA-Z/ if $new_options->{TRANSLATE_NAME};
		if ($seen->{$y} == 0) {
			push (@{ $options_file }, join("", "$y=", escape($new_options->{$x}), "\n"));
		}
		$GLOBAL_OPTIONS->{$y} = $new_options->{$x};
	}
	my @o = sort @{ $options_file };
	writefile("$DCONF->{admin_dir}/options.txt", \@o, "options_save", { no_lock => 1 });
	unlink "$DCONF->{admin_dir}/data/dtaskman.pid";
	unlink "$DCONF->{admin_dir}/data/schedule.pid";
	if (defined $new_options->{skinchoice} && $GLOBAL_OPTIONS->{tcache} == 2) {
		opendir(DIR, "$DCONF->{admin_dir}/data/tcache");
		my @z = map { join("/", $DCONF->{admin_dir}, "data", "tcache", $_) } grep { /^SKIN.*\.pl$/ } readdir (DIR);
		closedir(DIR);
		unlink @z;
		
	}
	return $GLOBAL_OPTIONS;
}

1;
