###############################################################################
# Attachments.pl                                                              #
###############################################################################
# YaBB: Yet another Bulletin Board                                            #
# Open-Source Community Software for Webmasters                               #
# Version:        YaBB 2.2.3                                                  #
# Packaged:       July 12, 2008                                               #
# Distributed by: http://www.yabbforum.com                                    #
# =========================================================================== #
# Copyright (c) 2000-2008 YaBB (www.yabbforum.com) - All Rights Reserved.     #
# Software by:  The YaBB Development Team                                     #
#               with assistance from the YaBB community.                      #
# Sponsored by: Xnull Internet Media, Inc. - http://www.ximinc.com            #
#               Your source for web hosting, web design, and domains.         #
###############################################################################

$attachmentsplver = 'YaBB 2.2.3 $Revision: 1.13.2.10 $';
if ($action eq 'detailedversion') { return 1; }

sub Attachments {
	&is_admin_or_gmod;

	fopen(AMS, "$vardir/attachments.txt");
	my @attachments = <AMS>;
	fclose(AMS);

	my $attachment_space = 0;
	foreach (@attachments) {
		$attachment_space += (split /\|/, $_, 7)[5];
	}

	my $remaining_space;
	if (!$dirlimit) {
		$remaining_space = "$fatxt{'23'}";
	} else {
		$remaining_space = ($dirlimit - $attachment_space) . " KB";
	}

	fopen(FILE, "$vardir/oldestattach.txt");
	$maxdaysattach = <FILE>;
	fclose(FILE);

	fopen(FILE, "$vardir/maxattachsize.txt");
	$maxsizeattach = <FILE>;
	fclose(FILE);

	my $totalattachnum = @attachments;
	$yymain .= qq~
<table border="0" width="70%" cellspacing="1" cellpadding="3" class="bordercolor" align="center">
<tr>
<td class="titlebg">
<img src="$imagesdir/xx.gif" alt="" />
<b>$fatxt{'24'}</b></td>
</tr><tr>
<td class="windowbg"><br /><span class="small">$fatxt{'25'}</span><br /><br /></td>
</tr><tr>
<td width="460" class="catbg"><b>$fatxt{'26'}</b></td>
</tr><tr>
<td class="windowbg" height="21">
<b>$fatxt{'27'}</b><br /></td>
</tr><tr>
<td class="windowbg2">
<table border="0" cellpadding="3" cellspacing="0"><tr>
<td><span class="small"><b>$fatxt{'28'}</b></span></td>
<td><span class="small">$totalattachnum</span></td>
</tr><tr>
<td><span class="small"><b>$fatxt{'29'}</b></span></td>
<td><span class="small">$attachment_space KB</span><br /></td>
</tr><tr>
<td><span class="small"><b>$fatxt{'30'}</b></span></td>
<td><span class="small">$remaining_space</span></td>
</tr>
</table><br />
</td>
</tr><tr>
<td class="windowbg" height="21">
<b>$fatxt{'31'}</b><br /></td>
</tr><tr>
<td class="windowbg2">
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<form action="$adminurl?action=removeoldattachments" method="post">
<td><span class="small">$fatxt{'32'}</span></td>
<td><span class="small"><input type="text" name="maxdaysattach" size="2" value="$maxdaysattach" /> $fatxt{'58'}&nbsp;</span></td>
<td><input type="submit" value="$admin_txt{'32'}" class="button" /></td>
</form>
</tr><tr>
<form action="$adminurl?action=removebigattachments" method="post">
<td><span class="small">$fatxt{'33'}</span></td>
<td><span class="small"><input type="text" name="maxsizeattach" size="2" value="$maxsizeattach" /> KB&nbsp;</span></td>
<td><input type="submit" value="$admin_txt{'32'}" class="button" /></td>
</form>
</tr><tr>
<td colspan="3"><span class="small" style="font-weight: bold;"><a href="$adminurl?action=manageattachments2">$fatxt{'31a'}</a></span> | <span class="small" style="font-weight: bold;"><a href="$adminurl?action=rebuildattach">$fatxt{'63'}</a></span></td>
</tr>
</table>
</td>
</tr>
</table>~;

	$yytitle = "$fatxt{'36'}";
	$action_area = "manageattachments";
	&AdminTemplate;
	exit;
}

sub RemoveOldAttachments {
	&is_admin_or_gmod;

	my $maxdaysattach = $FORM{'maxdaysattach'} || $INFO{'maxdaysattach'};
	if ($maxdaysattach !~ /^[0-9]+$/) { &admin_fatal_error("only_numbers_allowed"); }

	# Set up the multi-step action
	$time_to_jump = time() + $max_process_time;

	&automaintenance('on');

	opendir(ATT, $uploaddir) || &admin_fatal_error('cannot_open', "$uploaddir", 1);
	my @attachments = sort( grep(/\w+$/, readdir(ATT)) );
	closedir(ATT);

	fopen(AML, "$vardir/attachments.txt");
	my @attachmentstxt = <AML>;
	fclose(AML);
	chomp(@attachmentstxt);

	my (%att,@line);
	foreach (@attachmentstxt) {
		@line = split(/\|/, $_);
		$att{$line[7]} = $line[0];
	}

	my $info;
	if (!@attachments) {
		fopen(ATT, ">$vardir/attachments.txt") || &admin_fatal_error("cannot_open","$vardir/attachments.txt", 1);
		print ATT '';
		fclose(ATT);

		$info = qq~<br /><i>$fatxt{'48'}.</i>~;

	} else {
		unlink("$vardir/rem_old_attach.tmp") unless exists $INFO{'next'};

		my %rem_attachments;
		for (my $a = ($INFO{'next'} || 0); $a < @attachments; $a++) {
			# -M => Script start time minus file modification time, in days.
			my $age = sprintf("%.2f", -M "$uploaddir/$attachments[$a]");
			if ($age <= $maxdaysattach) {
				# If the attachment is not too old
				$info .= qq~<br />$attachments[$a] = $age $admin_txt{'122'}.~;

			} elsif (exists $att{$attachments[$a]}) {
				$rem_attachments{$att{$attachments[$a]}} .= $rem_attachments{$att{$attachments[$a]}} ? "|$attachments[$a]" : $attachments[$a];
				$info .= qq~<br /><i>$attachments[$a]</i> $fatxt{'1'} = $age $admin_txt{'122'}.~;
			}

			if ($time_to_jump < time() && ($a + 1) < @attachments) { 
				# save the $info of this run until the end of 'RemoveOldAttachments'
				fopen(FILE, ">>$vardir/rem_old_attach.tmp") || &admin_fatal_error('cannot_open', "$vardir/rem_old_attach.tmp", 1);
				print $info;
				fclose(FILE);

				$yySetLocation = qq~$adminurl?action=removeoldattachments;maxdaysattach=$maxdaysattach;next=~ . ($a + 1 - &RemoveAttachments(\%rem_attachments));
				&redirectexit;
			}
		}

		&RemoveAttachments(\%rem_attachments);
	}

	&automaintenance('off');

	$yymain .= qq~<b>$fatxt{'32'} $maxdaysattach $fatxt{'58'}.</b><br />~;

	fopen(FILE, "$vardir/rem_old_attach.tmp");
	$yymain .= join('', <FILE>) . $info;
	fclose(FILE);
	unlink("$vardir/rem_old_attach.tmp");

	fopen(FILE, ">$vardir/oldestattach.txt");
	print FILE $maxdaysattach;
	fclose(FILE);

	$yytitle     = "$fatxt{'34'} $maxdaysattach";
	$action_area = "removeoldattachments";
	&AdminTemplate;
	exit;
}

sub RemoveBigAttachments {
	&is_admin_or_gmod;

	my $maxsizeattach = $FORM{'maxsizeattach'} || $INFO{'maxsizeattach'};
	if ($maxsizeattach !~ /^[0-9]+$/) { &admin_fatal_error("only_numbers_allowed"); }

	# Set up the multi-step action
	$time_to_jump = time() + $max_process_time;

	&automaintenance('on');

	opendir(ATT, $uploaddir) || &admin_fatal_error('cannot_open', "$uploaddir", 1);
	my @attachments = sort( grep(/\w+$/, readdir(ATT)) );
	closedir(ATT);

	fopen(FILE, "$vardir/attachments.txt");
	@attachmentstxt = <FILE>;
	fclose(FILE);
	chomp(@attachmentstxt);

	my (%att,@line);
	foreach (@attachmentstxt) {
		@line = split(/\|/, $_);
		$att{$line[7]} = $line[0];
	}

	my $info;
	if (1 > @attachments) {
		fopen(ATT, ">$vardir/attachments.txt") || &admin_fatal_error("cannot_open","$vardir/attachments.txt", 1);
		print ATT '';
		fclose(ATT);

		$info = qq~<br /><i>$fatxt{'48'}.</i>~;

	} else {
		unlink("$vardir/rem_big_attach.tmp") unless exists $INFO{'next'};

		my (%rem_attachments,@line);
		for ($a = ($INFO{'next'} || 0); $a < @attachments; $a++) {
			my $size = sprintf("%.2f", ((-s "$uploaddir/$attachments[$a]") / 1024));
			if ($size <= $maxsizeattach) {
				# If the attachment is not too big
				$info .= qq~<br />$attachments[$a] = $size KB~;

			} elsif (exists $att{$attachments[$a]}) {
				$rem_attachments{$att{$attachments[$a]}} .= $rem_attachments{$att{$attachments[$a]}} ? "|$attachments[$a]" : $attachments[$a];
				$info .= qq~<br /><i>$attachments[$a]</i> $fatxt{'1'} = $size KB~;
			}

			if ($time_to_jump < time() && ($a + 1) < @attachments) { 
				# save the $info of this run until the end of 'RemoveBigAttachments'
				fopen(FILE, ">>$vardir/rem_big_attach.tmp") || &admin_fatal_error('cannot_open', "$vardir/rem_big_attach.tmp", 1);
				print $info;
				fclose(FILE);

				$yySetLocation = qq~$adminurl?action=removebigattachments;maxsizeattach=$maxsizeattach;next=~ . ($a + 1 - &RemoveAttachments(\%rem_attachments));
				&redirectexit;
			}
		}

		&RemoveAttachments(\%rem_attachments);
	}

	$yymain .= qq~<b>$fatxt{'33'} $maxsizeattach KB.</b><br />~;

	fopen(FILE, "$vardir/rem_big_attach.tmp");
	$yymain .= join('', <FILE>) . $info;
	fclose(FILE);
	unlink("$vardir/rem_big_attach.tmp");

	fopen(FILE, ">$vardir/maxattachsize.txt");
	print FILE $maxsizeattach;
	fclose(FILE);

	&automaintenance('off');

	$yytitle = "$fatxt{'35'} $maxsizeattach KB";
	$action_area = "removebigattachments";
	&AdminTemplate;
	exit;
}

sub Attachments2 {
	&is_admin_or_gmod;

	fopen(AML, "$vardir/attachments.txt");
	my @attachments = <AML>;
	fclose(AML);
	$attachcount = @attachments;

	my $action = $INFO{'action'};
	my $newstart = $INFO{'newstart'} || 0;

	if (1 > @attachments) {
		$viewattachments .= qq~<tr><td class="windowbg2" colspan="6"><center><b><i>$fatxt{'48'}</i></b></center></td></tr>~;

	} else {
		$viewattachments .= qq~
		<script language="JavaScript1.2" type="text/javascript">
		<!--
			function checkAll() {
  				for (var i = 0; i < document.del_attachments.elements.length; i++) {
					document.del_attachments.elements[i].checked = true;
	  			}
			}
			function uncheckAll() {
  				for (var i = 0; i < document.del_attachments.elements.length; i++) {
					document.del_attachments.elements[i].checked = false;
	  			}
			}
		//-->
		</script>

		<form name="del_attachments" action="$adminurl?action=deleteattachment" method="post" style="display: inline;">
		~;

		$postdisplaynum = 8;
		$max = $attachcount;
		$newstart = (int($newstart / 25)) * 25;
		$tmpa = 1;
		if ($newstart >= (($postdisplaynum - 1) * 25)) { $startpage = $newstart - (($postdisplaynum - 1) * 25); $tmpa = int( $startpage / 25 ) + 1; }
		if ($max >= $newstart + ($postdisplaynum * 25)) { $endpage = $newstart + ($postdisplaynum * 25); } else { $endpage = $max }
		if ($startpage > 0) { $pageindex = qq~<a href="$adminurl?action=$action;newstart=0" style="font-weight: normal;">1</a>&nbsp;...&nbsp;~; }
		if ($startpage == 25) { $pageindex = qq~<a href="$adminurl?action=$action;newstart=0" style="font-weight: normal;">1</a>&nbsp;~;}
		for ($counter = $startpage; $counter < $endpage; $counter += 25) {
			$pageindex .= $newstart == $counter ? qq~<b>$tmpa</b>&nbsp;~ : qq~<a href="$adminurl?action=$action;newstart=$counter" style="font-weight: normal;">$tmpa</a>&nbsp;~;
			$tmpa++;
		}
		$lastpn = int($attachcount / 25) + 1;
		$lastptn = ($lastpn - 1) * 25;
		if ($endpage < $max - (25) ) { $pageindexadd = qq~...&nbsp;~; }
		if ($endpage != $max) { $pageindexadd .= qq~<a href="$adminurl?action=$action;newstart=$lastptn">$lastpn</a>~; }
		$pageindex .= $pageindexadd;

		$pageindex = qq~
		<tr>
			<td class="windowbg" colspan="6"><span class="small" style="float: left;">$fatxt{'64'}: $pageindex</span></td>
		</tr>
		~;
		
		$numbegin = ($newstart + 1);
		$numend = ($newstart + 25);
		if ($numend > $attachcount) { $numend  = $attachcount; }
		if ($attachcount == 0) { $numshow = ''; }
		else { $numshow = qq~($numbegin - $numend)~; }

		@attach = splice(@attachments, $newstart, 25);
		undef @attachments;

		foreach $row (@attach) {
			chomp $row;
			my ($amthreadid, $amreplies, $amthreadsub, $amposter, $amcurrentboard, $amkb, $amdate, $amfn) = split(/\|/, $row);
			$amdate = &timeformat($amdate);
			if (length($amthreadsub) > 20) { $amthreadsub = substr($amthreadsub, 0, 20) . "..."; }
			$viewattachments .= qq~
		<tr>
		<td class="windowbg2" align="left" valign="middle"><a href="$uploadurl/$amfn" target="blank"> $amfn</a></td>
		<td class="windowbg2" align="left" valign="middle"> $amkb KB</td>
		<td class="windowbg2" align="left" valign="middle"> $amposter</td>
		<td class="windowbg2" align="left" valign="middle"> $amdate</td>
		<td class="windowbg2" align="left" valign="middle"> <a href="$scripturl?num=$amthreadid/$amreplies#$amreplies" target="blank">$amthreadsub</a></td>
		<td class="windowbg2" align="center" valign="middle"><input type="checkbox" name="del_$amthreadid" value="$amfn" /></td>
		</tr>\n~;
		}

		$viewattachments .= qq~
		$pageindex
		<tr>
		<td class="catbg" colspan="5" align="right">
		<input type="hidden" name="newstart" value="$newstart" />
		<input type="submit" value="$admin_txt{'32'}" class="button" /><span class="small">&nbsp; $amv_txt{'38'} &nbsp;</span>
		</td>
		<td class="catbg" align="center">
		<input type="checkbox" name="checkall" value="" onclick="if (this.checked) checkAll(); else uncheckAll();" />
		</td>
		</tr>
		</form>
		~;
	}

	$yymain .= qq~
<table border="0" cellspacing="1" cellpadding="3" class="bordercolor" align="center" width="90%">
<tr>
<td class="titlebg" colspan="6">
<img src="$imagesdir/xx.gif" alt="" border="0" />&nbsp;<b>$fatxt{'39'}</b>
</td>
</tr><tr>
<td class="windowbg" colspan="6">
<br />
<span class="small">$fatxt{'38'}</span>
<br /><br />
</td>
</tr>
<tr>
<td class="titlebg" colspan="6" align="center" width="100%"><b>$fatxt{'55'}</b></td>
</tr>
<tr>
<td class="titlebg" colspan="6" align="left" width="100%">
<span class="small">$fatxt{'28'} $attachcount $numshow</span>
</td>
</tr>
$pageindex
<tr>
<td class="catbg" align="center"><b>$fatxt{'40'}</b></td>
<td class="catbg" align="center"><b>$fatxt{'41'}</b></td>
<td class="catbg" align="center"><b>$fatxt{'42'}</b></td>
<td class="catbg" align="center"><b>$fatxt{'43'}</b></td>
<td class="catbg" align="center"><b>$fatxt{'44'}</b></td>
<td class="catbg" align="center"><b>$fatxt{'45'}</b></td>
</tr>
$viewattachments
</table>~;

	$yytitle = "$fatxt{'37'}";
	$action_area = "manageattachments";
	&AdminTemplate;
	exit;
}

sub DeleteAttachments {
	&is_admin_or_gmod;

	&automaintenance('on');

	my %rem_att;
	foreach (keys(%FORM)) {
		next unless $_ =~ /^del_(\d+)$/;
		my $thread = $1;
		$rem_att{$thread} = $FORM{$_};
		$rem_att{$thread} =~ s/, /|/g;
	}

	&RemoveAttachments(\%rem_att);

	&automaintenance('off');

	$yySetLocation = qq~$adminurl?action=manageattachments2;newstart=$FORM{'newstart'}~;
	&redirectexit;
}

sub FullRebuildAttachents {
	&is_admin_or_gmod();

	unless (defined $INFO{'boardnum'}) {
		&automaintenance('on');

		unlink "$vardir/newattachments.tmp";
		$yySetLocation = qq~$adminurl?action=rebuildattach;topicnum=0;boardnum=0~;
		&redirectexit();
	}

	# Set up the multi-step action
	$time_to_jump = time() + $max_process_time;

	# Get the board list from the forum.master file
	require "$boardsdir/forum.master";
	@boardlist = sort( keys(%board) );

	# Find the current board:
	my $curboard = $boardlist[$INFO{'boardnum'}];

	# Get the topic list.
	fopen(BOARD, "$boardsdir/$curboard.txt");
	my @topiclist = <BOARD>;
	fclose(BOARD);

	my ($topicnum,@newattachments,$mreplies,$msub, $mname, $mdate, $mfn, $nexttopic);
	for (my $i = $INFO{'topicnum'}; $i < @topiclist; $i++) {
		($topicnum, undef) = split(/\|/, $topiclist[$i], 2);
		fopen(TOPIC, "$datadir/$topicnum.txt");
		my @topic = <TOPIC>;
		fclose(TOPIC);
		chomp(@topic);

		$mreplies = 0;
		foreach (@topic) {
			($msub, $mname, undef, $mdate, undef, undef, undef, undef, undef, undef, undef, undef, $mfn) = split(/\|/, $_);
			if ($mfn ne '' && -e "$uploaddir/$mfn") {
				my $asize = int((-s "$uploaddir/$mfn") / 1024) || 1;
				push (@newattachments, qq~$topicnum|$mreplies|$msub|$mname|$curboard|$asize|$mdate|$mfn\n~);
			}
			$mreplies++;
		}

		if (time() > $time_to_jump && ($i + 1) < @topiclist) {
			$nexttopic = $i + 1;
			last;
		}
	}

	if (@newattachments) {
		fopen(AML, ">>$vardir/newattachments.tmp") || &admin_fatal_error('cannot_open', "$vardir/newattachments.tmp", 1);
		print AML @newattachments;
		fclose(AML);
	}

	# Prepare to continue...
	if ($nexttopic) { $INFO{'topicnum'} = $nexttopic; }
	else { $INFO{'boardnum'}++; $INFO{'topicnum'} = 0; }

	my $numleft = @boardlist - $INFO{'boardnum'};
	if ($numleft == 0) {
		fopen(AML, "$vardir/newattachments.tmp");
		my @newattachments = <AML>;
		fclose(AML);

		fopen (NEWFILE, ">$vardir/attachments.txt");
		print NEWFILE sort( { (split /\|/,$a)[6] <=> (split /\|/,$b)[6] } @newattachments);
		fclose (NEWFILE);
		unlink "$vardir/newattachments.tmp";

		&automaintenance("off");
		$yySetLocation = qq~$adminurl?action=remghostattach~;
		&redirectexit;
	}

	# Continue
	$action_area = 'manageattachments';
	$yytitle = "$fatxt{'37'}";

	$yymain .= qq~
		<br />
		$rebuild_txt{'1'}<br />
		$rebuild_txt{'5'} $max_process_time $rebuild_txt{'6'}<br />
		$rebuild_txt{'9'} $INFO{'boardnum'}/~ . @boardlist . qq~<br />
		<br />
		<div id="attachcontinued">
		$rebuild_txt{'2'} <a href="$adminurl?action=rebuildattach;topicnum=$INFO{'topicnum'};boardnum=$INFO{'boardnum'}" onclick="rebAttach();">$rebuild_txt{'3'}</a>
		</div>
	<script type="text/javascript" language="JavaScript">
	<!--
		function rebAttach() {
			document.getElementById("attachcontinued").innerHTML = '$rebuild_txt{'4'}';
		}

		function attachtick() {
			rebAttach();
			location.href="$adminurl?action=rebuildattach;topicnum=$INFO{'topicnum'};boardnum=$INFO{'boardnum'}";
		}

		setTimeout("attachtick()",3000)
	// -->
	</script>~;

	&AdminTemplate();
}

sub RemoveGhostAttach {
	&is_admin_or_gmod;

	$yymain .= qq~<b>$fatxt{'62'}</b><br /><br />~;

	fopen(AMS, "$vardir/attachments.txt");
	my @attachmentstxt = <AMS>;
	fclose(AMS);
	chomp(@attachmentstxt);

	my %att;
	foreach (@attachmentstxt) {
		$att{(split(/\|/, $_))[7]} = 1;
	}

	opendir(DIR, $uploaddir);
	my @filesDIR = grep(/\w+$/, readdir(DIR));
	close(DIR);

	$yymain .= qq~$fatxt{'61'}:<br />~;

	foreach my $fileinDIR (@filesDIR) {
		if (!$att{$fileinDIR}) {
			unlink "$uploaddir/$fileinDIR";
			$yymain .= qq~<br />$fatxt{'61b'}: $fileinDIR~;
		}
	}

	$yymain .= qq~<br /><br /><b>$fatxt{'61a'}</b>~;
	$yytitle = $fatxt{'61'};
	$action_area = 'manageattachments';
	&AdminTemplate;
	exit;
}

sub RemoveAttachments { # remove single or multiple attachments stored in a hash-reference
	my $count = 0;
	my $ThreadHashref = shift; # usage: ${$ThreadHashref}{'threadnum'} = 'filename1|filename2|...'
	                           # all attachments of thread are included if filname is undefined (undef)

	return $count if !%$ThreadHashref;

	fopen(AMP, "$vardir/attachments.txt", 1) || &admin_fatal_error("cannot_open","$vardir/attachments.txt", 1);
	my @attachments = <AMP>;
	fclose(AMP);
	chomp(@attachments);

	my ($athreadnum, $afilename);
	fopen(AMP, ">$vardir/attachments.txt", 1) || &admin_fatal_error("cannot_open","$vardir/attachments.txt", 1);
	for ($i = 0; $i < @attachments; $i++) {
		($athreadnum, undef, undef, undef, undef, undef, undef, $afilename) = split(/\|/, $attachments[$i]);
		my $del = 0;
		if (exists ${$ThreadHashref}{$athreadnum}) {
			if (defined ${$ThreadHashref}{$athreadnum}) {
				foreach (split(/\|/, ${$ThreadHashref}{$athreadnum})) {
					if ($_ eq $afilename) { $del = 1; last; }
				}
			} else {
				$del = 1;
			}
		}
		if ($del) {
			unlink("$uploaddir/$afilename");
			$count++;
		} else {
			print AMP "$attachments[$i]\n";
		}
	}
	fclose(AMP);

	$count;
}

1;