# UBB Private Message Routines : Perl Code

&RequireCode("$vars_config{CGIPath}/ubb_lib_posting.cgi");
&RequireCode("$vars_config{CGIPath}/ubb_lib_2.cgi");

# get assigned style template!
%vars_style = &LoadStyleTemplate($template_match{private_message});

$direct_to = qq!
<base href="$vars_config{NonCGIURL}/">
!;
&set_page_elements;

# make sure pm is enabled
if ($vars_pm{feature} eq 'off') {
	&StandardHTML("$vars_wordlets_err{pm_off}");
}

# make sure we have someone logged in
# (only registered members can pm)

if ($username eq '') {
	&StandardHTML(qq!$vars_wordlets_err{not_logged_in}<p> <a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=login">$vars_wordlets{login_now}</A> $vars_wordlets{or} <a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=agree">$vars_wordlets{register_title}</a></p>!);
}

# can remove this line after beta--
&make_pm_dirs;

sub pm_update_list {
	&CleanIN;    #ensure we're not getting bad input

	# $_[0] : ignore or buddy
	local (%pm_ignore, %pm_buddy, $key, $this_username);

	# collect all...
	foreach $key (keys %in) {
		if ($in{$key} eq 'include') {
			$pm_ignore{$key} = 'I';
		}
	}

	if ($_[0] eq 'ignore') {

		# collect all...
		foreach $key (keys %in) {
			if ($in{$key} eq 'include') {
				$this_username = &get_public_name($key);
				$this_username =~ s/\|/&#0124;/sg;
				if ($this_username =~ /\\$/) {
					$this_username .= ' ';
				}
				$pm_ignore{$key} = $this_username;
			}
		}

		# write to file
		&WriteHashToFile("$vars_config{MembersPath}/pm_ignore/$user_number.cgi", "pm_ignore", \%pm_ignore);

	} else {

		# collect all...
		foreach $key (keys %in) {
			if ($in{$key} eq 'include') {
				$this_username = &get_public_name($key);
				$this_username =~ s/\|/&#0124;/sg;
				if ($this_username =~ /\\$/) {
					$this_username .= ' ';
				}
				$pm_buddy{$key} = "$this_username";
			}
		}

		# write to file
		&WriteHashToFile("$vars_config{MembersPath}/pm_buddy/$user_number.cgi", "pm_buddy", \%pm_buddy);

	}

	%vars_style = &LoadStyleTemplate($template_match{transition});
	&set_page_elements;
	&Transition("$vars_config{CGIURL}/ultimatebb.cgi?ubb=my_profile", "$vars_wordlets{thanks_for_updating_list}", "$vars_wordlets{my_profile_header}");

}    # end pm_update_list

sub pm_do_list {
	&CleanIN;    #ensure we're not getting bad input

	# $_[0] : ignore or buddy

	local (%pm_ignore, %pm_buddy, $key, $list_count, $this_username);
	$list_count = 0;

	# retrieve list
	if (-e "$vars_config{MembersPath}/pm_$_[0]/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_$_[0]/$user_number.cgi");
	}

	my $list_add = &Do8Digit($in{u});

	$ThisHTML = qq~<html><head><title>$vars_config{BBName}</title>
<script language="javascript">
<!--
function closeWindow() {
		window.close();
}
//-->
</script>

</head><body>
<font face="$vars_style{FontFace}" size="$vars_style{TextSize}"><center>
<form>~;

	# can't send pm to self
	if ($list_add eq "$user_number") {
		$ThisHTML .= qq~$vars_wordlets_err{pm_list_add_self}<p></font>
<input type="button" value="$vars_wordlets{close_window}" onClick="closeWindow()"></center>
</form>
</p></body></html>~;
		print "$ThisHTML";
		exit(0);
	}

	if ($_[0] eq 'ignore') {

		foreach $key (keys %pm_ignore) {
			$list_count++;
		}

		if ($list_count >= 100) {
			$ThisHTML .= qq~$vars_wordlets_err{list_count_limit}~;
		} else {

			if (exists($pm_ignore{$list_add})) {
				$ThisHTML .= qq~$vars_wordlets{already_ignored}~;
			} else {
				$this_username = &get_public_name($list_add);
				$this_username =~ s/\|/&#0124;/sg;
				if ($this_username =~ /\\$/) { $this_username .= ' '; }
				$pm_ignore{$list_add} = $this_username;

				$ThisHTML .= qq~$vars_wordlets{ignore_added}~;

				# update ignore list
				&WriteHashToFile("$vars_config{MembersPath}/pm_ignore/$user_number.cgi", "pm_ignore", \%pm_ignore);

			}
		}

	} else {

		foreach $key (keys %pm_buddy) {
			$list_count++;
		}

		if ($list_count >= 100) {

			$ThisHTML .= qq~$vars_wordlets_err{list_count_limit}~;

		} else {

			if (exists($pm_buddy{$list_add})) {

				$ThisHTML .= qq~$vars_wordlets{already_buddy}~;

			} else {

				$this_username = &get_public_name($list_add);
				$this_username =~ s/\|/&#0124;/sg;
				if ($this_username =~ /\\$/) { $this_username .= ' '; }
				$pm_buddy{$list_add} = "$this_username";

				$ThisHTML .= qq~$vars_wordlets{buddy_added}~;

				# update buddy list
				&WriteHashToFile("$vars_config{MembersPath}/pm_buddy/$user_number.cgi", "pm_buddy", \%pm_buddy);
			}
		}
	}

	$ThisHTML .= qq~
</p></font>
<input type="button" value="$vars_wordlets{close_window}" onClick="closeWindow()"></center>
</form>
<p> </p>
~;

	print "$ThisHTML";
	exit(0);
}    # end pm_do_list

sub pm_list {
	&CleanIN;    #ensure we're not getting bad input

	# $_[0] : ignore or buddy

	local ($that_list, %pm_ignore, %pm_buddy, %pm_list, $key, $this_name, $count, $this_list, $list_explained, @pm_list);
	$count = 0;

	# retrieve list
	if (-e "$vars_config{MembersPath}/pm_$_[0]/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_$_[0]/$user_number.cgi");
	}

	$this_list = ucfirst($_[0]);
	$that_list = $_[0];

	if ($_[0] eq 'ignore') {
		$list_explained = $vars_wordlets{ignore_explained};
		%pm_list        = %pm_ignore;
	} else {
		$list_explained = $vars_wordlets{buddy_explained};
		%pm_list        = %pm_buddy;
	}

	# sort alphabetically
	@pm_list = sort { $pm_list{$a} cmp $pm_list{$b} } keys %pm_list;

	&set_page_elements;

	&LoadTemplate("public_pm_list");

}    # end pm_list

sub pm_check_full {
	if ((-e "$vars_config{MembersPath}/pm_users/$_[0].cgi") && ($_[0] ne '')) {
		&RequireVars("$vars_config{MembersPath}/pm_users/$_[0].cgi");
	}
	my $index_count = 0;

	foreach $key (keys %pm_user_index) {
		$index_count++;
	}

	foreach $key (keys %pm_user_index_sent) {
		$index_count++;
	}

	if ($index_count > 59) {
		&StandardHTML("$vars_wordlets_err{pm_user_max}");
	}
}    # end check full

sub pm_reply {
	&CleanIN;    #ensure we're not getting bad input
	local (%pm_user_index, %pm_user_index_sent, %pm_topic_data, %pm_date, %pm_time, %pm_post, %pm_icon, %pm_to, %pm_from, %pm_signature, @pm_profile, $ubb_images, $j, $is_html, $is_ubb, $html_allowed, $ubb_allowed, $ubb_images_wording, $icon_field, $show_sig, $disable_smilies, $close_option, @user_profile, $ubb_code_buttons, $pm_to_name, $page_title, $form_hiddens, $breadcrumb, $subject_field);

	# page title:
	$page_title = "$vars_wordlets{pm_reply}";

	# get pm topic!
	if (-e "$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi");
	} else {
		&StandardHTML("$vars_wordlets_err{no_such_pm}");
	}

	# are add'l replies allowed?
	if ($pm_topic_data{replies} > 20) {
		&StandardHTML("$vars_wordlets{pm_full_explained}");
	}

	# can't reply to self
	if ($user_number eq "$pm_topic_data{from}") {
		&StandardHTML("$vars_wordlets_err{cant_reply_to_self2}");
	}

	# is recipient's pm box full?
	&pm_check_full($pm_topic_data{from});

	# subject field:
	$subject_field = qq~$pm_topic_data{subject}~;

	# is user on ignore?
	&check_ignore($pm_topic_data{from});

	# get profile for recipient
	@pm_profile = &OpenProfile($pm_topic_data{from});
	chomp($pm_profile[15]);
	chomp($pm_profile[0]);
	$pm_to_name = $pm_profile[15];
	if ($pm_to_name eq '') { $pm_to_name = $pm_profile[0]; }

	chomp($pm_profile[27]);
	if ($pm_profile[27] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_off_for_member}");
	}


	my $mystatus = "";
	my @iam      = &OpenProfile($user_number);
	if (@iam) { $mystatus = $iam[8] }


	# are only forum leaders permitted to receive pm?
	if (($vars_pm{feature} eq 'leaders_only') && (($pm_profile[8] !~ m/^(Admin|Mod)/)    #user is an adminmod
	    || ($mystatus !~ m/^(Admin|Mod)/)))    #sender is an adminmod

	{
		&StandardHTML("$vars_wordlets_err{pm_only_leaders} 1");
	}

	# has admin disabled PM for sender?
	@user_profile = &verify_id_num($username, $password, $user_number);
	chomp($user_profile[29]);
	if ($user_profile[29] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_ban}");
	}

	if ($vars_pm{html} eq 'on') {
		$is_html      = "$vars_wordlets{html_is_on}";
		$html_allowed = "yes";
	} else {
		$is_html      = "$vars_wordlets{html_is_off}";
		$html_allowed = "no";
	}

	if ($vars_pm{ubb_code} ne 'off') {
		$is_ubb      = "$vars_wordlets{ubbcode_is_on}";
		$ubb_allowed = 'yes';
	} else {
		$is_ubb      = "$vars_wordlets{ubbcode_is_off}";
		$ubb_allowed = 'no';
	}

	if ($vars_pm{ubb_code} eq 'images_off') {
		$ubb_images_wording = "$vars_wordlets{ubbcode_images_banned}";
	} else {
		$ubb_images_wording = '';
	}

	if ($vars_pm{ubb_code} ne 'off') {
		$ubb_code_buttons = &instant_ubb_code;
	} else {
		$ubb_code_buttons = "$is_ubb";
	}

	if ($vars_display{AllowIcons} eq 'TRUE') {
		$icon_field = &create_icon_field("1");
	}

	# show signature?
	if ($vars_display{AllowSignature} eq 'YES') {
		$show_sig = qq(<br /><input type="CHECKBOX" id="Signature" name="Signature" value="yes" checked="checked" /> $vars_wordlets{show_signature});
	}

	# disable smilies?
	$disable_smilies = qq(<br /><input type="CHECKBOX" id="disable_smilies" name="disable_smilies" value="yes" /> $vars_wordlets{disable_smilies});

	# close PM?
	$close_option = qq(<br /><input type="CHECKBOX" id="close_pm" name="close_pm" valye="yes" /> <B>$vars_wordlets{close_pm}</B>);

	# breadcrumb
	$breadcrumb = qq~<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=my_profile">$vars_wordlets{my_profile_header}</a> &#187;<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=get_pm&d=$in{d}&t=$in{t}">$pm_topic_data{subject}</a> &#187; $vars_wordlets{pm_reply}~;

	# hiddens
	$form_hiddens = qq~
<input type="HIDDEN" id="ubb" name="ubb" value="submit_pm_reply" />
<input type="HIDDEN" id="d" name="d" value="$in{d}" />
<input type="HIDDEN" id="t" name="t" value="$in{t}" />
~;

	# pull in instant smilie/ubb code javascript
	$direct_to .= $instant_jscript;
	&set_page_elements;

	&LoadTemplate("public_pm_form");

}    # end pm_reply

sub pm_delete {
	&CleanIN;    #ensure we're not getting bad input
	local (%pm_topic_data, %pm_date, %pm_time, %pm_post, %pm_icon, %pm_to, %pm_from, %pm_signature, %pm_user_index, %pm_user_index_sent);

	# make sure pm topic exists!
	if (-e "$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi") {

		&RequireVars("$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi");

		if (($user_number ne $pm_topic_data{to}) && ($user_number ne $pm_topic_data{from})) {
			&StandardHTML("$vars_wordlets_err{not_pm_recipient}");
		}

	} else {
		&StandardHTML("$vars_wordlets_err{no_such_pm}");
	}

	# delete topic file

	$pm_topic_data{"deleted_$user_number"} = 1;
	if (($pm_topic_data{"deleted_$pm_topic_data{from}"}) && ($pm_topic_data{"deleted_$pm_topic_data{to}"})) {
		unlink("$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi") or die "$! - $in{d}, $in{t}";
	} else {
		&update_pm_topic($in{d}, $in{t});
	}

	my $stringer = $in{d} . "-" . $in{t};

	# update user pm file
	if (-e "$vars_config{MembersPath}/pm_users/$user_number.cgi") {

		&RequireVars("$vars_config{MembersPath}/pm_users/$user_number.cgi");

		delete($pm_user_index{$stringer});
		delete($pm_user_index_sent{$stringer});

		my $thispartichash = ();    #can't do a WriteHashesToFile - need to manip hashes during a write

		$thispartichash .= qq!\%pm_user_index = (\n!;
		foreach $key (keys %pm_user_index) {
			next if $key eq $stringer;
			delete $pm_user_index_sent{$key} if (exists($pm_user_index{$key}));
			$thispartichash .= qq!"$key" => "$pm_user_index{$key}",\n!;
		}
		$thispartichash .= qq!);\n!;

		$thispartichash .= qq!\%pm_user_index_sent = (\n!;
		foreach $key (keys %pm_user_index_sent) {
			next if $key eq $stringer;
			$thispartichash .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
		}
		$thispartichash .= qq!);\n!;
		$thispartichash .= qq!1;\n!;

		&WriteFileAsString("$vars_config{MembersPath}/pm_users/$user_number.cgi", $thispartichash);

		$thispartichash = "";

	}

	&StandardHTML(qq~$vars_wordlets{thanks_for_topic_delete}. <p>$vars_wordlets{view} <a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=my_profile">$vars_wordlets{my_profile_header}</a>.~);

}    # end pm_close

sub get_pm {
	&CleanIN;    #ensure we're not getting bad input
	local (%pm_topic_data, %pm_date, %pm_time, %pm_post, %pm_icon, %pm_to, %pm_from, %pm_signature, $alt_color, $topic_closed, $topic_wording, $reply_wording, $this_icon, $ThisDate, $FormatTime, $profile_link, $homepage_link, $email_link, $post_body, $AuthorExtra, $user_status, $member_number, $show_public_name, $RegDate, $RegMonth, $RegDay, $RegMon, $RegYear, @themonths, $u, $post_total_line, $location_line, $regdate_line, @author_extra, $allow_images, $key, $topic_full, $pipestem, $to_name, $add_user_2_list);
	local (*FILE);

	# for registration date...
	@themonths = ('', "$vars_wordlets_date{month_1_abbrev}", "$vars_wordlets_date{month_2_abbrev}", "$vars_wordlets_date{month_3_abbrev}", "$vars_wordlets_date{month_4_abbrev}", "$vars_wordlets_date{month_5_abbrev}", "$vars_wordlets_date{month_6_abbrev}", "$vars_wordlets_date{month_7_abbrev}", "$vars_wordlets_date{month_8_abbrev}", "$vars_wordlets_date{month_9_abbrev}", "$vars_wordlets_date{month_10_abbrev}", "$vars_wordlets_date{month_11_abbrev}", "$vars_wordlets_date{month_12_abbrev}");

	# make sure user requesting pm is the recipient!
	if (-e "$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi") {

		&RequireVars("$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi");

		if (($user_number ne $pm_topic_data{to}) && ($user_number ne $pm_topic_data{from})) {
			&StandardHTML("$vars_wordlets_err{not_pm_recipient}");
		}

	} else {
		&StandardHTML("$vars_wordlets_err{no_such_pm}");
	}

	# is pm topic closed?
	if ($pm_topic_data{close} eq 'yes') {
		$pipestem      = '';
		$topic_closed  = qq(<br clear=all><font size="1"><img src="$vars_config{NonCGIURL}/lock.gif" border="0" alt="$vars_wordlets{topic_closed}">&nbsp;&nbsp;$vars_wordlets{topic_closed}</font>);
		$reply_wording = '';
	} else {
		$pipestem     = ' | ';
		$topic_closed = qq~&#171; <a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=pm_delete&d=$in{d}&t=$in{t}">$vars_wordlets{pm_delete}</a> &#187;~;

		# max: 20 replies
		if ($pm_topic_data{replies} == 20) {
			$reply_wording = qq!$vars_wordlets{pm_full}!;
			$topic_full    = qq!$vars_wordlets{pm_full_explained}!;
		} else {
			$reply_wording = qq!<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=pm_reply&d=$in{d}&t=$in{t}"><acronym title="$vars_wordlets{pm_reply_explained}">$vars_wordlets{send_pm_reply}</acronym></a>!;
		}

	}

	$topic_wording = qq!$pipestem<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=private_message&u=$pm_topic_data{from}"><acronym title="$vars_wordlets{new_pm_explained}">$vars_wordlets{new_private_message}</acronym></a>!;

	# get public name of Sender
	$to_name = &get_public_name($pm_topic_data{from});

	$direct_to .= qq~

<script language="javascript">
<!--
function ignore()
{
var listWindow = window.open('$vars_config{CGIURL}/ultimatebb.cgi?ubb=do_ignore&u=$pm_topic_data{from}','_blank','toolbar=no, menubar=no,location=no,directories=no,status=no,width=275,height=200,top=200,left=200');
}
function buddy()
{
var listWindow = window.open('$vars_config{CGIURL}/ultimatebb.cgi?ubb=do_buddy&u=$pm_topic_data{from}','_blank','toolbar=no, menubar=no,location=no,directories=no,status=no,width=275,height=200,top=200,left=200');
}
//-->
</script>
~;

	&set_page_elements;
	&LoadTemplate("public_pm_topic");

	$add_user_2_list = &list_check("$pm_topic_data{from}");

	$ThisHTML = $Header;
	$ThisHTML .= &topic_top;

	$alt_color = $vars_style{AltColumnColor2};

	# loop through all posts in pm
	foreach (0 .. $pm_topic_data{replies}) {
		undef($show_public_name);
		undef($user_status);
		undef($email_link);
		undef($AuthorExtra);
		undef($member_number);
		undef(@user_profile);
		undef($profile_link);

		# format date
		$ThisDate = &DateFormat($pm_date{$_});

		# format time
		$FormatTime = &TimeFormat($pm_time{$_});

		# grab post message
		$post_body = $pm_post{$_};

		# get user profile
		@user_profile = &OpenProfile($pm_from{$_});
		chomp($user_profile[0]);
		chomp($user_profile[15]);
		chomp($user_profile[2]);
		chomp($user_profile[6]);
		chomp($user_profile[7]);
		chomp($user_profile[10]);
		chomp($user_profile[12]);
		chomp($user_profile[8]);

		# get public name
		$show_public_name = $user_profile[15];
		if ($show_public_name eq '') { $show_public_name = $user_profile[0]; }

		# do some cleaning---
		$user_profile[6] =~ s/<.+?>//g;
		$user_profile[6] =~ s/<.*//g;     # delete unclosed HTML tags

		# get custom title
		if (!$user_profile[31]) {
			$user_status = &CustomTitle($user_profile[8]);
		} else {
			$user_status = $user_profile[31];
		}

		# registration date for user
		$RegDate = $user_profile[10];

		if ($RegDate eq '') {
			$RegDate = "$vars_wordlets{pre_reg_date_wording}";
		} else {
			($RegMon, $RegDay, $RegYear) = split (/-/, $RegDate);
			$RegMonth = $themonths[$RegMon];
			$RegDate  = "$RegMonth $RegYear";
		}

		# member_number:
		$u             = $pm_from{$_} + 0;                          # rid extra zeros from member no.
		$member_number = "$vars_wordlets{user_number_abbrev} $u";

		# author info options
		undef($post_total_line);
		undef($location_line);
		undef($regdate_line);
		undef(@author_extra);

		if ($vars_display{author_post_total} eq 'yes') {
			$post_total_line = qq( $vars_wordlets{author_posts} <b>$user_profile[7]</b> );
			push (@author_extra, $post_total_line);
		}

		if ($vars_display{author_location} eq 'yes') {
			$location_line = qq( $vars_wordlets{author_from} <b>$user_profile[6]</b> );
			push (@author_extra, $location_line);
		}

		if ($vars_display{author_reg_date} eq 'yes') {
			$regdate_line = qq( $vars_wordlets{author_registered} <b>$RegDate</b> );
			push (@author_extra, $regdate_line);
		}

		if ($author_extra[0]) {
			$AuthorExtra = join ("|", @author_extra);
		} else {
			$AuthorExtra = '';
		}

		$profile_link = qq(<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=get_profile&u=$pm_from{$_}" target="_blank">
<img src="$vars_config{NonCGIURL}/$vars_style{profilegif}" border="0" alt="$vars_wordlets{view_profile_for} $show_public_name"></a>);

		if (($vars_display{EmailBlock} eq 'ON') || ($user_profile[11] eq 'no')) {
			$email_link = '&nbsp;';
		} else {

			$email_link = qq(&nbsp;&nbsp;<a href="$vars_config{CGIURL}/ultimatebb.cgi?ubb=email&ToWhom=$pm_from{$_}" target="_blank"><img src="$vars_config{NonCGIURL}/$vars_style{mailgif}" border="0" alt="$vars_wordlets{send_email_to} $show_public_name"></a>&nbsp;&nbsp;);
		}

		# add signature, if necessary
		if ($pm_signature{$_} eq 'yes') {

			# new format! - signature is not included in message
			if (($vars_display{AllowSignature} eq 'YES') && ($user_profile[12] ne '')) {

				if ($vars_display{AllowSignatureImage} eq 'YES') {
					$allow_images = 'ON';
				} else {
					$allow_images = 'OFF';
				}

				$user_profile[12] = &UBBCode($user_profile[12], $allow_images);
				$post_body .= ("<p>$vars_wordlets{signature_break}</p><p>$user_profile[12]</p>");
			}
		}

		# message icons?
		if ($vars_display{AllowIcons} eq 'TRUE') {
			$icon_number = $pm_icon{$_};
			if ($icon_number eq '') { $icon_number = '1'; }
			unless (-e "$vars_config{NonCGIPath}/icons/icon$icon_number.gif") {
				$icon_number = '1';
			}
			$this_icon = qq(<img src="$vars_config{NonCGIURL}/icons/icon$icon_number.gif" border="0" align="ABSCENTER">);
		} else {
			$this_icon = qq(<img src="$vars_config{NonCGIURL}/posticon.gif" border="0" align="ABSCENTER">);
		}

		$ThisHTML .= &topic_row;
	}

	$ThisHTML .= &topic_bottom;

	$ThisHTML .= $Footer;
	print "$ThisHTML";

	# mark pm as read, if not already so marked!
	if ($pm_topic_data{"read_$user_number"} eq 'no') { &mark_read($in{d}, $in{t}); }

}    # end get_pm

sub mark_read {
	$pm_topic_data{"read_$user_number"} = "yes";
	$pm_topic_data{"read"}              = "yes";

	# post to pm_topics directory
	&update_pm_topic($in{d}, $in{t});

}    # end mark_read

sub update_pm_topic {

	# $_[0]: pm directory
	# $_[1}: pm topic

	my @namers  = qw(pm_topic_data pm_date pm_time pm_post pm_to pm_from pm_icon pm_signature);
	my @hashers = (\%pm_topic_data, \%pm_date, \%pm_time, \%pm_post, \%pm_to, \%pm_from, \%pm_icon, \%pm_signature);
	my $names   = \@namers;
	my $hashes  = \@hashers;

	&WriteHashesToFile("$vars_config{MembersPath}/pm_topics/$_[0]/$_[1].cgi", $names, $hashes);

}    #end update_pm_topic

sub check_ignore {

	# $_[0]: user number of potential recipient
	if ((-e "$vars_config{MembersPath}/pm_ignore/$_[0].cgi") && ($_[0] ne '')) {
		&RequireVars("$vars_config{MembersPath}/pm_ignore/$_[0].cgi");
	}

	if (exists($pm_ignore{$user_number})) {
		&StandardHTML("$vars_wordlets_err{pm_ignore_ban}");
	}
}    # end check_ignore

sub private_message {
	&CleanIN;    #ensure we're not getting bad input
	local (@pm_profile, $ubb_images, $j, $is_html, $is_ubb, $html_allowed, $ubb_allowed, $ubb_images_wording, $icon_field, $show_sig, $disable_smilies, $close_option, @user_profile, $ubb_code_buttons, $pm_to_name, $page_title, $form_hiddens, $breadcrumb, $subject_field, %pm_ignore);

	# can't send pm to self
	if ($in{u} eq "$user_number") {
		&StandardHTML("$vars_wordlets_err{pm_to_self}");
	}

	# check the member number
	unless ($in{u} =~ /^\d{8}$/) {
		&StandardHTML("$vars_wordlets_err{no_member_number} $in{u}");
	}

	# page title:
	$page_title = "$vars_wordlets{send_private_message}";

	# subject_field:
	$subject_field = q~<input type="TEXT" name="topic_subject" id="topic_subject" value='' size="40" maxlength="85" />~;

	# breadcrumb
	$breadcrumb = "$vars_wordlets{send_private_message}";

	@pm_profile = &OpenProfile($in{u});

	chomp($pm_profile[27]);
	if ($pm_profile[27] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_off_for_member}");
	}


	my $mystatus = "";
	my @iam      = &OpenProfile($user_number);
	if (@iam) { $mystatus = $iam[8] }


	# are only forum leaders permitted to receive pm?
	if (($vars_pm{feature} eq 'leaders_only') && (($pm_profile[8] !~ m/^(Admin|Mod)/)    #user is an adminmod
	    || ($mystatus !~ m/^(Admin|Mod)/)))    #sender is an adminmod

	{
		&StandardHTML("$vars_wordlets_err{pm_only_leaders} 2");
	}

	# is sender on ignore list?
	# retrieve list
	&check_ignore($in{u});

	# get name of person sending PM to:
	chomp($pm_profile[0]);
	chomp($pm_profile[15]);
	$pm_to_name = $pm_profile[15];
	if ($pm_to_name eq '') { $pm_to_name = $pm_profile[0]; }

	# has admin disabled PM for sender?
	# also checks members Queue
	@user_profile = &verify_id_num($username, $password, $user_number);
	chomp($user_profile[29]);
	if (($user_profile[29] eq 'no') || ($user_profile[26] =~ /Q/)) {
		&StandardHTML("$vars_wordlets_err{pm_ban}");
	}

	if ($vars_pm{html} eq 'on') {
		$is_html      = "$vars_wordlets{html_is_on}";
		$html_allowed = "yes";
	} else {
		$is_html      = "$vars_wordlets{html_is_off}";
		$html_allowed = "no";
	}

	if ($vars_pm{ubb_code} ne 'off') {
		$is_ubb      = "$vars_wordlets{ubbcode_is_on}";
		$ubb_allowed = 'yes';
	} else {
		$is_ubb      = "$vars_wordlets{ubbcode_is_off}";
		$ubb_allowed = 'no';
	}

	if ($vars_pm{ubb_code} eq 'images_off') {
		$ubb_images_wording = "$vars_wordlets{ubbcode_images_banned}";
	} else {
		$ubb_images_wording = '';
	}

	if ($vars_pm{ubb_code} ne 'off') {
		$ubb_code_buttons = &instant_ubb_code;
	} else {
		$ubb_code_buttons = "$is_ubb";
	}

	if ($vars_display{AllowIcons} eq 'TRUE') {
		$icon_field = &create_icon_field("1");
	}

	# show signature?
	if ($vars_display{AllowSignature} eq 'YES') {
		$show_sig = qq(<br /><input type="CHECKBOX" name="Signature" id="Signature" value="yes" checked="checked"> $vars_wordlets{show_signature});
	}

	# disable smilies?
	$disable_smilies = qq(<br /><input type="CHECKBOX" id="disable_smilies" name="disable_smilies" value="yes"> $vars_wordlets{disable_smilies});

	# close PM?
	$close_option = qq(<br /><input type="CHECKBOX" name="close_pm"  id="close_pm" value="yes"> <b>$vars_wordlets{close_pm}</b>);

	# hiddens
	$form_hiddens = qq~
<input type="HIDDEN" id="ubb" name="ubb" value="submit_private_message" />
<input type="HIDDEN" id="u" name="u" value="$in{u}" />
~;

	# pull in instant smilie/ubb code javascript
	$direct_to .= $instant_jscript;
	&set_page_elements;

	&LoadTemplate("public_pm_form");

}    # end new_reply_page

sub submit_pm {
	&CleanIN;    #ensure we're not getting bad input
	local (@pm_profile, @user_profile, $ip_number, $j, $pm_to_name, @ip_banlist, %pm_user_index, %pm_user_index_sent, $html_body, $last_num, $email_message, $html_message, $ubb_images);
	local (*FILE);

	# Require english letter/number in subject?
	if (($in{topic_subject} !~ /[a-zA-Z0-9]/) && ($vars_misc{EnglishSubjectCheck} eq "ON")) {
		&StandardHTML("$vars_wordlets_err{subject_deficient}");
	}

	# check for HTML tags in subject
	if (($in{topic_subject} =~ /<.*>/) || ($in{topic_subject} =~ /</)) {
		&StandardHTML("$vars_wordlets_err{subject_with_html}");
	}

	$vars_misc{runOnLimit} = 30 unless $vars_misc{runOnLimit};

	# other subject checks/clean-ups
	if ($in{topic_subject} =~ /\S{$vars_misc{runOnLimit}}/) {
		&StandardHTML("$vars_wordlets_err{subject_with_runontext} : $in{topic_subject}");
	}    #test before trying to expand special characters

	$in{topic_subject} = FixSubjectEncoding($in{topic_subject});

	# make sure hiddens are cool
	unless ($in{u} =~ /^\d{8}$/) {
		&StandardHTML("$vars_wordlets_err{invalid_input}");
	}

	# can't send pm to self
	if ($in{u} eq "$user_number") {
		&StandardHTML("$vars_wordlets_err{pm_to_self}");
	}

	# is user banned?
	$ip_number = $ENV{'REMOTE_ADDR'};
	&check_ip_bans;

	# is user on ignore?
	&check_ignore($in{u});

	#validate
	my @ValidateArray = ("message", "u", "topic_subject");
	&Validate(@ValidateArray);

	# get profile for PM Sender
	@user_profile = &verify_id_num($username, $password, $user_number);

	# get profile for PM Receiver
	@pm_profile = &OpenProfile($in{u});

	# does receiver want to receive PM?
	chomp($pm_profile[27]);
	if ($pm_profile[27] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_off_for_member}");
	}

	# get name of person sending PM to:
	chomp($pm_profile[0]);
	chomp($pm_profile[15]);
	$pm_to_name = $pm_profile[15];
	if ($pm_to_name eq '') { $pm_to_name = $pm_profile[0]; }


	my $mystatus = "";
	my @iam      = &OpenProfile($user_number);
	if (@iam) { $mystatus = $iam[8] }


	# check to see if PM set to leaders_only
	if (($vars_pm{feature} eq 'leaders_only') && (($pm_profile[8] !~ m/^(Admin|Mod)/)    #user is an adminmod
	    || ($mystatus !~ m/^(Admin|Mod)/)))    #sender is an adminmod

	{
		&StandardHTML("$vars_wordlets_err{pm_only_leaders} 3");
	}

	# has admin disabled PM for sender?
	chomp($user_profile[29]);
	if ($user_profile[29] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_ban}");
	}

	# floodcheck
	if ($vars_misc{FloodCheck} eq 'ON') {

		#floodcheck courtesy of Michael Farris
		chomp($user_profile[8]);
		&floodcheck unless (($user_profile[8] eq 'Administrator') || ($user_profile[8] eq 'Moderator'));
	}

	# determine last PM number and increment by 1
	if (-e "$vars_config{MembersPath}/pm_info/pm_last_number.cgi") {
		$last_num = &OpenFileAsVar("$vars_config{MembersPath}/pm_info/pm_last_number.cgi");

	} else {
		$last_num = 0;
	}

	my $pm_topic = $last_num + 1;
	$pm_topic = &Do8Digit($pm_topic);
	my $topic_directory = &random_directory;

	$message = $in{message};

	# if HTML is not allowed, render it useless
	if ($vars_pm{html} eq 'off') {
		$message =~ s/</&lt;/g;
		$message =~ s/>/&gt;/g;
	} else {

		# don't allow HTML SCRIPT TAGS
		&check_html($message);
	}

	$message = &CensorCheck("$message");
	$message = &Truncate("$message");

	$message_ascii = $message;

	# do graemlins--
	if ($in{disable_smilies} ne 'yes') { $message = &Smilies("$message"); }

	# UBB Code-ify (if allowed)
	if ($vars_pm{ubb_code} ne 'off') {

		if ($vars_pm{ubb_code} eq 'images_off') {
			$ubb_images = 'OFF';
		} else {
			$ubb_images = 'ON';
		}
		$message = &UBBCode("$message", "$ubb_images");
	}    #end if UBB Code allowed

	#convert newlines/carriage returns to <br> and <p> html tags
	$message = &ConvertReturns("$message");

	# check for excess images-
	&excess_smilies_check($message);

	# escape pipestems
	$message =~ s/\|/&#0124;/sg;
	$in{topic_subject} =~ s/\|/&#0124;/sg;

	# escape ending backslashes
	if ($message =~ /\\$/) {
		$message .= ' ';
	}
	if ($in{topic_subject} =~ /\\$/) {
		$in{topic_subject} .= ' ';
	}

	# set post icon
	unless ($in{msg_icon} >= 0) { $in{msg_icon} = '1'; }

	# need to send message, subject, to, from, icon,
	unless (-d "$vars_config{MembersPath}/pm_topics/$topic_directory") {
		mkdir("$vars_config{MembersPath}/pm_topics/$topic_directory", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_topics/$topic_directory");
	}

	# post to pm_topics directory

	%pm_topic_data = (
		"subject"           => $in{topic_subject},
		"replies"           => "0",
		"close"             => "$in{close_pm}",
		"to"                => "$in{u}",
		"from"              => "$user_number",
		"read"              => "no",
		"read_$user_number" => "no",
		"read_$in{u}"       => "no",
	);

	%pm_date = (
		"0" => "$GotTime{HyphenDate}",
	);

	%pm_time = (
		"0" => "$GotTime{Time}",
	);

	%pm_post = (
		"0" => $message,
	);

	%pm_to = (
		"0" => "$in{u}",
	);

	%pm_from = (
		"0" => "$user_number",
	);

	%pm_icon = (
		"0" => "$in{msg_icon}",
	);

	%pm_signature = (
		"0" => "$in{Signature}",
	);

	&update_pm_topic($topic_directory, $pm_topic);

	# update Receiver pm_user file
	# is recipient's pm box full? - also grabs %pm_user_index and %pm_user_index_sent
	&pm_check_full($in{u});

	# set this for pm notify:
	$in{t} = $pm_topic;
	$in{d} = $topic_directory;

	# %pm_user_index grabbed
	my $index_number = ("$topic_directory-$pm_topic");
	$pm_user_index{$index_number} = $GotTime{LastLoginJulian};

	my $userindexstring = "";    #another write while manip - can't do WriteHashesToFile

	$userindexstring .= qq!\%pm_user_index = (\n!;
	foreach $key (keys %pm_user_index) {
		delete $pm_user_index_sent{$key} if (exists($pm_user_index{$key}));
		$userindexstring .= qq!"$key" => "$pm_user_index{$key}",\n!;
	}
	$userindexstring .= qq!);\n!;

	$userindexstring .= qq!\%pm_user_index_sent = (\n!;
	foreach my $key (keys %pm_user_index_sent) {
		$userindexstring .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
	}
	$userindexstring .= qq!);\n!;

	$userindexstring .= qq!1;\n!;

	&WriteFileAsString("$vars_config{MembersPath}/pm_users/$in{u}.cgi", $userindexstring);

	$userindexstring = "";



	%pm_user_index      = ();
	%pm_user_index_sent = ();
	if (-e "$vars_config{MembersPath}/pm_users/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_users/$user_number.cgi");
	}
	$pm_user_index_sent{$index_number} = $GotTime{LastLoginJulian};

	my $anotheruserindex = "";    #yes, again...

	$anotheruserindex .= qq!\%pm_user_index = (\n!;
	foreach my $key (keys %pm_user_index) {
		$anotheruserindex .= qq!"$key" => "$pm_user_index{$key}",\n!;
	}
	$anotheruserindex .= qq!);\n!;

	$anotheruserindex .= qq!\%pm_user_index_sent = (\n!;
	foreach my $key (keys %pm_user_index_sent) {
		$anotheruserindex .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
	}
	$anotheruserindex .= qq!);\n!;

	$anotheruserindex .= qq!1;\n!;

	&WriteFileAsString(">$vars_config{MembersPath}/pm_users/$user_number.cgi", $anotheruserindex);

	$anotheruserindex = "";

	# update last number file:
	&WriteFileAsString("$vars_config{MembersPath}/pm_info/pm_last_number.cgi", "$pm_topic\n");

	# update pm counter file:
	if (-e "$vars_config{MembersPath}/pm_info/pm_counter.cgi") {
		my $pm_counter = &OpenFileAsVar("$vars_config{MembersPath}/pm_info/pm_counter.cgi");
	} else {
		$pm_counter = 0;
	}
	$pm_counter++;

	&WriteFileAsString("$vars_config{MembersPath}/pm_info/pm_counter.cgi", "$pm_counter\n");

	# send email notification to receiver?
	chomp($pm_profile[28]);
	if (($pm_profile[28] ne 'no') && ($vars_email{UseEmail} eq 'ON')) {

		# set email template
		%vars_style = &LoadStyleTemplate($template_match{email});
		&RequireCode("$vars_config{CGIPath}/ubb_lib_mail.cgi");
		&RequireVars("$vars_config{VariablesPath}/vars_wordlets_email.cgi");

		if ($vars_email{email_format} ne 'html') {
			$email_message = qq!$vars_wordlets_email{pm_notify}!;
		} else {
			$email_message = '';
		}

		if ($vars_email{email_format} ne 'ascii') {
			$html_body    = qq!<font face="$vars_style{FontFace}" size="$vars_style{TextSize}">! . "$vars_wordlets_email{pm_notify_html}" . qq!</font>!;
			$html_message = "$EmailHeader $html_body $Footer";
		} else {
			$html_message = '';
		}

		chomp($pm_profile[2]);

		# reply to -> SELF
		&ubb_mail("$pm_profile[2]", "$vars_display{BBEmail}", "$pm_profile[2]", "", "$vars_wordlets_email{pm_notify_subject} : $in{topic_subject} : $pubname", "$email_message", "$html_message", '');

	}

	%vars_style = &LoadStyleTemplate($template_match{private_message});
	# no cache to clear!
	# on screen
	if ($in{refer} eq '') {
		$in{refer} = "$vars_config{CGIURL}/ultimatebb.cgi";
	}
	%vars_style = &LoadStyleTemplate($template_match{transition});
	&set_page_elements;
	&Transition("$in{refer}", "$vars_wordlets{thanks_for_pm}", "$in{refer}");
	exit(0);
}    # end submit pm

sub submit_pm_reply {
	&CleanIN;    #ensure we're not getting bad input
	local (%pm_topic_data, %pm_date, %pm_time, %pm_post, %pm_icon, %pm_to, %pm_from, %pm_signature, @pm_profile, @user_profile, $ip_number, $j, $pm_to_name, @ip_banlist, %pm_user_index, %pm_user_index_sent, $html_body, $last_num, $email_message, $html_message, $ubb_images);
	local (*FILE);

	# is user banned?
	$ip_number = $ENV{'REMOTE_ADDR'};
	&check_ip_bans;

	#validate
	my @ValidateArray = ("d", "t", "message");
	&Validate(@ValidateArray);

	# get pm topic!
	if (-e "$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_topics/$in{d}/$in{t}.cgi");
	} else {
		&StandardHTML("$vars_wordlets_err{no_such_pm}");
	}

	# are add'l replies allowed?
	if ($pm_topic_data{replies} > 20) {
		&StandardHTML("$vars_wordlets{pm_full_explained}");
	}

	# can't reply to self
	if ($user_number eq "$pm_topic_data{from}") {
		&StandardHTML("$vars_wordlets_err{cant_reply_to_self2}");
	}

	# is user on ignore?
	&check_ignore($pm_topic_data{from});

	# get profile for PM Sender
	@user_profile = &verify_id_num($username, $password, $user_number);

	# get profile for PM Receiver
	@pm_profile = &OpenProfile($pm_topic_data{from});

	# does receiver want to receive PM?
	chomp($pm_profile[27]);
	if ($pm_profile[27] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_off_for_member}");
	}

	# get name of person sending PM to:
	chomp($pm_profile[0]);
	chomp($pm_profile[15]);
	$pm_to_name = $pm_profile[15];
	if ($pm_to_name eq '') { $pm_to_name = $pm_profile[0]; }


	my $mystatus = "";
	my @iam      = &OpenProfile($user_number);
	if (@iam) { $mystatus = $iam[8] }


	# check to see if PM set to leaders_only
	if (($vars_pm{feature} eq 'leaders_only') && (($pm_profile[8] !~ m/^(Admin|Mod)/)    #user is an adminmod
	    || ($mystatus !~ m/^(Admin|Mod)/)))    #sender is an adminmod

	{
		&StandardHTML("$vars_wordlets_err{pm_only_leaders} 4");
	}

	# has admin disabled PM for sender?
	chomp($user_profile[29]);
	if ($user_profile[29] eq 'no') {
		&StandardHTML("$vars_wordlets_err{pm_ban}");
	}

	# is topic closed?
	if ($pm_topic_data{close} eq 'yes') {
		&StandardHTML("$vars_wordlets_err{topic_closed}");
	}

	# floodcheck
	if ($vars_misc{FloodCheck} eq 'ON') {

		#floodcheck courtesy of Michael Farris
		chomp($user_profile[8]);
		&floodcheck unless (($user_profile[8] eq 'Administrator') || ($user_profile[8] eq 'Moderator'));
	}

	# determine last PM number and increment by 1
	if (-e "$vars_config{MembersPath}/pm_info/pm_last_number.cgi") {
		$last_num = &OpenFileAsVar("$vars_config{MembersPath}/pm_info/pm_last_number.cgi");

	} else {
		$last_num = 0;
	}

	$message = $in{message};

	# if HTML is not allowed, render it useless
	if ($vars_pm{html} eq 'off') {
		$message =~ s/</&lt;/g;
		$message =~ s/>/&gt;/g;
	} else {

		# don't allow HTML SCRIPT TAGS
		&check_html($message);
	}

	$message = &CensorCheck("$message");
	$message = &Truncate("$message");

	$message_ascii = $message;

	# do graemlins--
	if ($in{disable_smilies} ne 'yes') { $message = &Smilies("$message"); }

	# UBB Code-ify (if allowed)
	if ($vars_pm{ubb_code} ne 'off') {

		if ($vars_pm{ubb_code} eq 'images_off') {
			$ubb_images = 'OFF';
		} else {
			$ubb_images = 'ON';
		}
		$message = &UBBCode("$message", "$ubb_images");
	}    #end if UBB Code allowed

	#convert newlines/carriage returns to <br> and <p> html tags
	$message = &ConvertReturns("$message");

	# check for excess images-
	&excess_smilies_check($message);

	# escape pipestems
	$message =~ s/\|/&#0124;/sg;
	if ($message =~ /\\$/) { $message .= ' '; }

	# set post number
	my $thispost = $pm_topic_data{replies} + 1;
	$pm_post{$thispost} = $message;

	# set post icon
	unless ($in{msg_icon} >= 0) { $in{msg_icon} = '1'; }
	$pm_icon{$thispost} = $in{msg_icon};

	# set to/from
	$pm_to{$thispost}   = $pm_topic_data{from};
	$pm_from{$thispost} = $pm_topic_data{to};
	$pm_topic_data{to}   = $pm_to{$thispost};
	$pm_topic_data{from} = $pm_from{$thispost};

	# other fields...
	$pm_signature{$thispost} = $in{Signature};
	$pm_date{$thispost}      = $GotTime{HyphenDate};
	$pm_time{$thispost}      = $GotTime{Time};
	$pm_topic_data{replies} = $thispost;

	# make sure topic dir exists
	unless (-d "$vars_config{MembersPath}/pm_topics/$in{d}") {
		mkdir("$vars_config{MembersPath}/pm_topics/$in{d}", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_topics/$in{d}");
	}

	# is recipient's pm box full? - also grabs %pm_user_index and  %pm_user_index_sent
	&pm_check_full($pm_topic_data{to});

	# update pm topic file

	# reset read states
	$pm_topic_data{"read_$pm_topic_data{from}"} = "no";
	$pm_topic_data{"read_$pm_topic_data{to}"}   = "no";
	foreach (keys %pm_topic_data) {	# reset delete states
		delete $pm_topic_data{"$_"} if m/^deleted_/;
	}

	&update_pm_topic($in{d}, $in{t});

	# update Receiver pm_user file
	# %pm_user_index grabbed
	my $index_number = ("$in{d}-$in{t}");
	$pm_user_index{$index_number} = $GotTime{LastLoginJulian};

	my $yetanotherstring = "";    #Again!?

	$yetanotherstring .= qq!\%pm_user_index = (\n!;
	foreach $key (keys %pm_user_index) {
		delete $pm_user_index_sent{$key} if (exists($pm_user_index{$key}));
		$yetanotherstring .= qq!"$key" => "$pm_user_index{$key}",\n!;
	}
	$yetanotherstring .= qq!);\n!;

	$yetanotherstring .= qq!\%pm_user_index_sent = (\n!;
	foreach my $key (keys %pm_user_index_sent) {
		$yetanotherstring .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
	}
	$yetanotherstring .= qq!);\n!;

	$yetanotherstring .= qq!1;\n!;

	&WriteFileAsString("$vars_config{MembersPath}/pm_users/$pm_topic_data{to}.cgi", $yetanotherstring);

	$yetanotherstring = "";

	# update sender's user index - remove this topic
	undef(%pm_user_index);
	undef(%pm_user_index_sent);
	if (-e "$vars_config{MembersPath}/pm_users/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_users/$user_number.cgi");
	}
	delete $pm_user_index{$index_number};
	$pm_user_index_sent{$index_number} = $GotTime{LastLoginJulian};

	my $gettingtiredofthis = "";    #okey, this is annoying

	$gettingtiredofthis .= qq!\%pm_user_index = (\n!;
	foreach $key (keys %pm_user_index) {
		delete $pm_user_index_sent{$key} if (exists($pm_user_index{$key}));
		$gettingtiredofthis .= qq!"$key" => "$pm_user_index{$key}",\n!;
	}
	$gettingtiredofthis .= qq!);\n!;

	$gettingtiredofthis .= qq!\%pm_user_index_sent = (\n!;
	foreach $key (keys %pm_user_index_sent) {
		$gettingtiredofthis .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
	}
	$gettingtiredofthis .= qq!);\n!;

	$gettingtiredofthis .= qq!1;\n!;

	&WriteFileAsString("$vars_config{MembersPath}/pm_users/$user_number.cgi", $gettingtiredofthis);

	$gettingtiredofthis = "";

	# update pm counter file:
	if (-e "$vars_config{MembersPath}/pm_info/pm_counter.cgi") {
		my $pm_counter = &OpenFileAsVar("$vars_config{MembersPath}/pm_info/pm_counter.cgi");
	} else {
		$pm_counter = 0;
	}
	$pm_counter++;

	&WriteFileAsString("$vars_config{MembersPath}/pm_info/pm_counter.cgi", "$pm_counter\n");

	# send email notification to receiver?
	chomp($pm_profile[28]);
	if (($pm_profile[28] ne 'no') && ($vars_email{UseEmail} eq 'ON')) {

		$in{topic_subject} = $pm_topic_data{subject};

		%vars_style = &LoadStyleTemplate($template_match{email});
		&RequireCode("$vars_config{CGIPath}/ubb_lib_mail.cgi");

		if ($vars_email{email_format} ne 'html') {
			&RequireVars("$vars_config{VariablesPath}/vars_wordlets_email.cgi");
			$email_message = qq!$vars_wordlets_email{pm_notify}!;
		} else {
			$email_message = '';
		}

		if ($vars_email{email_format} ne 'ascii') {
			$message = &ConvertReturns($message_ascii);
			&RequireVars("$vars_config{VariablesPath}/vars_wordlets_email.cgi");
			$html_body    = qq!<font face="$vars_style{FontFace}" size="$vars_style{TextSize}">! . "$vars_wordlets_email{pm_notify_html}" . qq!</font>!;
			$html_message = "$EmailHeader $html_body $Footer";
		} else {
			$html_message = '';
		}

		chomp($pm_profile[2]);

		# reply to -> SELF
		&ubb_mail("$pm_profile[2]", "$vars_display{BBEmail}", "$pm_profile[2]", '', "$vars_wordlets_email{pm_notify_subject} : $pm_topic_data{subject} : $pubname", "$email_message", "$html_message", '');

	}

	# no cache to clear!

	# on screen
	%vars_style = &LoadStyleTemplate($template_match{transition});
	&set_page_elements;
	&Transition("$vars_config{CGIURL}/ultimatebb.cgi?ubb=my_profile", "$vars_wordlets{thanks_for_pm}", "$vars_wordlets{my_profile_header}");
}    # end submit_pm_reply

sub random_directory {
	my @letters = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Y', 'Z');
	srand(time);
	my $num1 = rand(@letters);
	return ($letters[$num1]);
}

sub make_pm_dirs {
	unless (-d "$vars_config{MembersPath}/pm_users") {
		mkdir("$vars_config{MembersPath}/pm_users", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_users");
	}

	unless (-d "$vars_config{MembersPath}/pm_topics") {
		mkdir("$vars_config{MembersPath}/pm_topics", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_topics");
	}
	unless (-d "$vars_config{MembersPath}/pm_info") {
		mkdir("$vars_config{MembersPath}/pm_info", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_info");
	}

	unless (-d "$vars_config{MembersPath}/pm_ignore") {
		mkdir("$vars_config{MembersPath}/pm_ignore", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_ignore");
	}
	unless (-d "$vars_config{MembersPath}/pm_buddy") {
		mkdir("$vars_config{MembersPath}/pm_buddy", 0777);
		chmod(0777, "$vars_config{MembersPath}/pm_buddy");
	}
}    # end make_pm_dirs

sub pm_prune {
	&CleanIN;    #ensure we're not getting bad input
	local ($key, %pm_user_index, %pm_user_index_sent, $pm_dir, $pm_topic, $this_key);

	# grab pm_users file
	if (-e "$vars_config{MembersPath}/pm_users/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_users/$user_number.cgi");
	} else {
		&StandardHTML("$vars_wordlets_err{pm_nothing_to_delete}");
	}

	# delete from user record and delete actual pm topic
	my $pm_prune_count = 0;

	foreach $key (keys %in) {
		if ($key =~ /delete/) {
			$pm_prune_count++;
			$this_key = $in{$key};
			delete($pm_user_index{$this_key});
			delete($pm_user_index_sent{$this_key});
			($pm_dir, $pm_topic) = split (/-/, $this_key);

			#unlink("$vars_config{MembersPath}/pm_topics/$pm_dir/$pm_topic.cgi");

			if (-e "$vars_config{MembersPath}/pm_topics/$pm_dir/$pm_topic.cgi") {

				&RequireVars("$vars_config{MembersPath}/pm_topics/$pm_dir/$pm_topic.cgi");

				if (($user_number ne $pm_topic_data{to}) && ($user_number ne $pm_topic_data{from})) {
					&StandardHTML("$vars_wordlets_err{not_pm_recipient}");
				}

			} else {
				&StandardHTML("$vars_wordlets_err{no_such_pm}");
			}

			$pm_topic_data{"deleted_$user_number"} = 1;
			if (($pm_topic_data{"deleted_$pm_topic_data{from}"}) && ($pm_topic_data{"deleted_$pm_topic_data{to}"})) {
				unlink("$vars_config{MembersPath}/pm_topics/$pm_dir/$pm_topic.cgi") or die "$! - $pm_dir, $pm_topic";
			} else {
				&update_pm_topic($pm_dir, $pm_topic);
			}
		}
	}

	# update user index file

	my $stringification = "";    # *twitch*

	$stringification .= qq!\%pm_user_index = (\n!;
	foreach $key (keys %pm_user_index) {
		delete $pm_user_index_sent{$key} if (exists($pm_user_index{$key}));
		$stringification .= qq!"$key" => "$pm_user_index{$key}",\n!;
	}
	$stringification .= qq!);\n!;

	$stringification .= qq!\%pm_user_index_sent = (\n!;
	foreach $key (keys %pm_user_index_sent) {
		$stringification .= qq!"$key" => "$pm_user_index_sent{$key}",\n!;
	}
	$stringification .= qq!);\n!;

	$stringification .= qq!1;\n!;

	&WriteFileAsString("$vars_config{MembersPath}/pm_users/$user_number.cgi", $stringification);

	$stringification = "";

	# in case they did not select any PMs to delete--
	unless ($pm_prune_count > 0) {
		&StandardHTML("$vars_wordlets_err{no_pm_selected}");
	}

	# on screen confirmation
	%vars_style = &LoadStyleTemplate($template_match{transition});
	&set_page_elements;
	&Transition("$vars_config{CGIURL}/ultimatebb.cgi?ubb=my_profile", "$vars_wordlets{thanks_for_pm_prune}", "$vars_wordlets{my_profile_header}");
}    # end pm_prune

sub sent_pm_box {
	&CleanIN;    #ensure we're not getting bad input
	local (@pm_topics, $pm_count, $pm_rec_count);

	# get pm topics for user
	if (-e "$vars_config{MembersPath}/pm_users/$user_number.cgi") {
		&RequireVars("$vars_config{MembersPath}/pm_users/$user_number.cgi");
	}

	# sort %pm_user_index
	@pm_topics = sort { $pm_user_index_sent{$b} <=> $pm_user_index_sent{$a} } keys %pm_user_index_sent;

	# pm max warning
	$pm_count = $pm_rec_count = 0;
	foreach $key (keys %pm_user_index_sent) {
		$pm_count++;
	}

	foreach $key (keys %pm_user_index) {
		$pm_rec_count++;
	}

	&LoadTemplate("public_pm_sent_box");

}    #endsub


sub CleanIN {
	if ($in{d}) { &StandardHTML($vars_wordlets_err{bad_input}) if ($in{d} !~ m/^[A-Z]$/); }
	if ($in{u}) { &StandardHTML($vars_wordlets_err{bad_input}) if ($in{u} !~ m/^\d{8}$/); }
	if ($in{t}) { &StandardHTML($vars_wordlets_err{bad_input}) if ($in{t} !~ m/^\d{8}$/); }
}    #endsub


# DANGER: Do not remove the next line!
1;
