#!/usr/bin/perl
# licensed under GNU GPL, 2001 by The Yes Men
# Version: $Name:  $

use Socket; # required in Perl 5 
use File::Basename; 
use File::Copy; # for moving the pending savefile to the final accomplished one
use Time::Local; # for timegm when figuring out file age
use FileHandle;

require 'flush.pl';


# todo: microsoft, the links don't work....

# TODO: delete cache periodically (option)
# TODO: alternate domain for e-mail addresses

# Global variables:

# $g_deftagendmarks = "\"'>\#\?\\s\\\\\\(\\)\\\@é";  # this variable is obsolete, replaced by $g_startdelims
$g_startdelims  = '"\'\s\\\(\)\@='; # what sets off filenames, basically, at the start.
	# (don't want to deal with parameters)
	# Why on earth is the @ in there?
	# Leaving the ( and ) in there, even though ( only makes sense for start and ) for end--shouldn't matter.

$g_permissions = 0777; # was all 0755

$g_perlpath = $perlpath;

$g_dbgfilesizechecked = 0;
$g_sublistsfigured = 0;
@g_sublists = ( );
$g_sublist = $sublist;

$g_fluffmode = $fluffmode;
$g_flufflist = $flufflist;

$g_myemail = $myemail;

$g_dontuseHTTP10 = $dontuseHTTP10;

$g_nomod = 1; # detected automatically--passed from y.pl if mod_rewrite, in g_stubtype
$g_stubtype = "php3"; # passed, detected
$g_slashplaceholder = $slashfile; 
$g_slashplaceholder =~ s/\.htm[l]?$//;

$g_startfilemark = "é"; # @"; # something that can't exist in a url...
$g_newlinemark = "$g_startfilemark" . "newylineynewywheewheehahanewlinewhoa";

$g_neveroverwritecached = $neveroverwritecached;
$g_absolutelyneveroverwritecached = $absolutelyneveroverwritecached;

$g_stealemails = $stealemails;
$g_rewritefullurls = $rewritefullurls;
$g_givemealsospecific = $givemealsospecific;
$g_givemealsogreedy = $givemealso;
$g_sublinesparsed = 0;
$g_checkdomsparsed = 0;
# @g_tagsublines = ( );
@g_sublines = ( );
@g_flufflines = ( );
@g_matchurls = ( );
$g_pendingext = "\.tmp-pending";
$g_basepath = 0;
$g_cachedir = $cachedir;
$g_cachedir_mod_rewrite = $cachedir_mod_rewrite;

# todo: get mod_rewrite option working again!!

$g_metakeywords = $metakeywords;
$g_metadesc = $metadesc;

$g_smartsubstitutions = $smartsubstitutions;

$g_dbgtabs = -1; # for nice indenting--gets incremented at start of dealwithfile, for example
$g_dbgfileraw = $dbgfile;
$g_dbgfile = 0;
$g_dbgfh = 0;
$g_dbgfilesizelimit = $dbgfilesizelimit;
$g_dbgverbose = $dbgverbose;
$g_dbgveryverbose = $dbgveryverbose;

$g_givemedomain = $givemedomain;
$g_twoletters = 0; # if 0, will figure it out from givemedomain
$g_threeletters = 0; # if 0, will figure it out from givemedomain
$g_allletters = 0; # must be 0--will figure it out from givemedomain
$g_referer = $referer;
$g_mademimehash = 0;
$g_weblocation = $putithere;
$g_mydomain = 0;
$g_mybaredomain = 0;
$g_cgiurl = $cgiurl;
$g_variablesinited = 0;
$g_subdomstr = "/affiliates";
$g_socketconnecttime = $socketconnecttime; # in seconds
unless ($g_socketconnecttime) { $g_socketconnecttime = 15; }
$g_killtime = $killtime;
unless ($g_killtime) { $g_killtime = 240; }	
$g_cachetime = $cachetime;

$g_killflash = $killflash;

$g_pixelfile = "reamweaverpixel.gif";

$g_remoteaddr = 0;

$g_cacheparams = $cacheparams;

# end global variables

# todo: try to get working for javascript of dupont

sub dealwithfile {
	my ($file, $pleasetoscreen, $basepath, $markbasepath, $prm, $desiredsfn, $stubtype, $remoteaddr, $savingdirname) = @_;
	dbgvv("entering dealwithfile");
	$g_dbgtabs = $g_dbgtabs + 1;

	my $errorcode = 0;
	my $askedtolockpending = 0; # number of times have tried to lock the temporary (pending) output file
	FAILEDTOLOCK: my $boop = 1;

	my @lines; # the lines of the html file (if any) -- for in eval loop
	# my @cachelines; # for storage, in case decide not to use

	my $toscreen;


	# moved lines below into eval in case makedirectories or other stuff was problem...
	init($remoteaddr, $basepath, $stubtype);

	my $outfile;
	if ($file eq "") {
		dbgv("BLANK FILE in dealwithfile??");
		$file = "/"; # just so doesn't give nothing
	}
	if (!$stubtype) { if ($file =~ /\/$/) { dbgv("strangely, no stubtype for index $file"); } }



	my $dontusecached = 0;
	my $paramstring = "";
	# note: below only works for $g_nomod; for it to work with !$g_nomod, would have to
	# figure out in .htaccess how to substitute a & for the ?, and so on...
	if ($prm) {
		if ($g_stubtype eq "cgi" || !$g_nomod) { # doubt it works for !$g_nomod, but you never know...
			my $sizeprm = @$prm;
			if ($sizeprm > 0) {
				dbgv("got parameters: $sizeprm parameters");
				$paramstring = "?";
				my $pae;
				foreach $pae(@$prm) {
					$paramstring = "$paramstring$pae&";
				}
				$paramstring =~ s/&$//;
				dbgv("final paramstring, to be passed when making request in socketRequest, is:\n\t$paramstring");
				if (!$g_cacheparams && !$g_absolutelyneveroverwritecached) {
					$dontusecached = 1;
				}
			}
		}
		else {
			dbgv("got a parameter $prm here with $g_stubtype--will just prefix a ?");
			$paramstring= "?$prm";
			if (!$g_cacheparams && !$g_absolutelyneveroverwritecached) {
				$dontusecached = 1;
			}
		}
	}
	my $getdomain = $g_givemedomain;
	my $subdomain = 0;
	my $port; # for in eval loop


	my $savefilename = 0;
	my $savefilenamepending = 0;
	if ($g_nomod) {
		my $regexstartjunk = "$g_basepath"; # hack
		if ($g_cachedir) {
			$regexstartjunk = "$regexstartjunk/$g_cachedir";
		}
		$regexstartjunk =~ s|\.|\\\.|g;
		$file =~ s/^$regexstartjunk//; # ????? should work i guess...
	}
	if ($g_basedir) {
		if (!$g_nomod) {
			$file =~ s/^$g_basedir//;
		}
	}
	my $rawfile = $file;
	if ($file =~ /^$g_subdomstr/) {
		$file =~ s|^$g_subdomstr\/||;
		my $suburl = $file;
		($subdomain, $file) = SplitURL($suburl, 0);
		if (!$file) {
			$file = "/";
			dbgv("file blank in $suburl (subdomain: $subdomain); setting file to $file ".
				"(note: paramstring: $paramstring)");
		}
		$getdomain = $subdomain;
		if ($g_mybaredomain) {
			$getdomain =~ s/$g_mybaredomain/$g_givemebaredomain/; # convert back from masking
		}
		if ($getdomain eq $g_givemedomain) { # might make sense to do this later too... or... hm....
			$subdomain = 0; 
		}
	}

	my $sfn;
	if (!$g_nomod) {
		if ($desiredsfn) {
			dbg("HMMMMMMMM.... unexpected desiredsfn($desiredsfn) in dealwithfile, with not-mod version");
		}
		$sfn = "$g_basepath/$g_cachedir_mod_rewrite/$getdomain$file";
	}
	else {
		if (!$desiredsfn) {
			$sfn = $g_basepath;
			if ($g_cachedir) { $sfn = "$sfn/$g_cachedir"; }
			$sfn = "$sfn$rawfile"; # if $g_nomod, then just put it at e.g. ../yesiwill/example/images/dog.jpg
			if ($g_cacheparams && $prm) {
				my $pstring = $paramstring;
				$pstring =~ s/\&/=amp=/g;
				$pstring =~ s/\?/=questionmark=/g;
				$sfn = "$sfn$pstring";
				dbgv("since had params, cached file name is now $sfn");
				# so parameters to things get stored in different cache files--that is so that
				# http://www.reamweaver.com/example/r/index.php.hi.php?section1=practices&section2=marketing
				# can get cached somewhere (other than in.hi.html))
			}
		}
		else {
			dbgv("setting sfn to desiredsfn: $desiredsfn");
			$sfn = $desiredsfn;
		}
	}
	my $istobeparsed = 0;
	my $canbespewed = 0; 	# output to screen if $toscreen and $canbespewed
				# if $toscreen but not $canbespewed--then redirect at end
	if (!($g_stubtype =~ /php/)) {
		$canbespewed = 1; # always can be unless php
	} 
	my $isjavascriptfile = 0;
	my $isjavascript = 0; # is used in eval
	my $isslash = 0;
	my $storablesfn = $sfn;
	if ($sfn =~ /\/$/) {
		# if ($desiredsfn) { dbg("HMMMMMMM... weird that desiredsfn ends with a slash, no?? ($desiredsfn)"); }
		$isslash = 1;
		$storablesfn = "$storablesfn$g_slashplaceholder.html";
	}
	# dow; todo: good to eventually just add something before the extension, always, to make it different...
	elsif ($sfn =~ /index\.htm[l]?$/ || $sfn =~ /welcome\.htm[l]?$/ || $sfn =~ /default\.htm[l]?$/) {
		$storablesfn = "$storablesfn.$g_slashplaceholder.html"; # just so that it doesn't work as a real html page...
	}

	# if the length of $storablesfn is greater than 100, just abort.... it's probably an endless r0/r0/r0/r0/ thing....
	my $maxsfnlength = 150;
	my $sfnlength = length($storablesfn);
	if ($sfnlength > $maxsfnlength) {
		
		my $errmess = "ERROR: path $storablesfn is too long ($sfnlength > $maxsfnlength); aborting";
		dbg($errmess);
		printtoscreen($errmess);
		exit(0);

	}


	my $mimetype = &mimefind($sfn);
	if ($mimetype eq 'text/html') { 
		$istobeparsed = 1;
		$canbespewed = 1;
	}

	if (!$istobeparsed) {
		if ($sfn =~ /\.htm[l]?$/ || $sfn =~ /\.asp$/ || $sfn =~ /\.txt$/ || $sfn =~ /\.php$/ || 
						$sfn =~ /\.dll$/ || $isslash || $sfn =~ /\.twhat$/) {
			dbg("NOTE: mimetype ($mimetype) was not text/html, but the ending of file is probably html?\n\t$sfn\n----");
			$istobeparsed = 1;
			$canbespewed = 1;
		}
	}
	if ($sfn =~ /\.js/) { # We want to parse this, but we want to be aware that it's Javascript.
		if ($mimetype ne "application/x-javascript") { dbgv("hmm, that's weird"); } # should replace end-check with this
		$isjavascriptfile = 1;
		$istobeparsed = 1;
	}
	if ($sfn =~ /\.css/) { # strangely, sometimes has url references
		if ($mimetype ne "text/css") { dbgv("hmm, that's css weird"); } # should replace end-check with this
		$isjavascriptfile = 1; # hack--change var name
		$istobeparsed = 1;
	}
	if ($mimetype eq 'text/plain' || $mimetype eq 'text/rtf' || 
				$mimetype eq 'application/msword' || $mimetype eq 'application/pdf' || 
				$mimetype eq 'application/wordperfect') {
		dbgv("will parse $mimetype");
		$istobeparsed = 1; # cannot be spewed, however, by php
	}


	# TESTING below
	# now, try making the $storablesfn something that won't conflict with a dirctory just in case
	# we've got a directory name by accident (rather than a file): example from weforum.org, homepublic.nsf
	# note: didn't fix the homepublic.nsf problem... which is actually weirder: it gets to writing:
  	# 	for (i=0; i<(args.length-2); i+=3) if ((obj=MM_
	# in the in.wef.html.tmp-pending-1
	# and then hangs. no idea why.
	if (0) {
		my $tmpdebugstorablesfn = $storablesfn;
		if ($storablesfn =~ s|(.*)\.([^/\.]*)$|$1\.$g_threeletters\.$2|) {
			dbgv("since storable sfn ending with .-something, made it: $storablesfn (was: $tmpdebugstorablesfn)");
		}
		else {
			dbgv("didn't contain .-something: $storablesfn");
		}
	}

	unless( -e $storablesfn) {
		makedirectories($storablesfn); # makes dirs if they don't exist already
	}

	$toscreen = $pleasetoscreen && $canbespewed; # this is if can actually write the lines to the screen as they are
		# come across--if not, will write the whole file to disk, and at end redirect to the written file.
	$savefilename = $storablesfn;
	$savefilenamepending = "$savefilename$g_pendingext"; # for writing to until satisfyingly finished
	# end of moved into eval


	my $happywithcached; # for in eval loop
	my $beganwriting = 0;	
	my $startoutline = 0;
	$_ = $getdomain;
	/^([^:]*):*([^ ]*)/;
	$getdomain = $1;
	$port = $2;
	$port = 80 unless $port;

	# if cached file very young, don't even make request, just grab the lines from cached version
	my $cachetimeelapsed = 0;
	my $savefiletime = 0; # so can pass it to ParseResponseHeaders
	# if socket request times out (because host is down), just serve up the cached version
	if (!$dontusecached && (-s $savefilename)) { # so far, only reason can be that parms were passed...
		# check to see if sublist or reamweaver.conf has been modified since savefilename was cached;
		# do this whether or not $g_neveroverwritecached is set.
		if (!$g_absolutelyneveroverwritecached && $istobeparsed) {
		# if ($istobeparsed) {
			$savefiletime = (stat $savefilename) [9];
			my @sublists = GetSubListNames($g_basepath);
			my $sublist;
			foreach $sublist(@sublists) {
				if (-s $sublist) { # if not, we have problems, later...
					my $sublisttime = (stat $sublist) [9];
					if ($sublisttime > $savefiletime) {
						dbgv("because $sublist modified after $savefilename, re-cache");
						fixsublisttime($sublist, $sublisttime);
						$dontusecached = 1;
						# last;
					}
					else { dbgv("$sublist older than $savefilename, ok"); }
				}
				else { dbgv("WEIRD--couldn't find sublist $sublist"); }
			}
			# todo: check also to see if reamweaver.conf has been modified since savefilename was cached
		}
		if (!$dontusecached) { # if still going, check and see if modified longer ago than cachetime
			if ($g_neveroverwritecached || $g_absolutelyneveroverwritecached || 
						((-M $savefilename)*24*60 < $g_cachetime)) { 
				# if ($g_neveroverwritecached) { 
				# 	dbgv("because set neveroverwritecached in conf, using cached"); 
				# }
				# dbgv("using recently cached $savefilename");
				if (open(IN, $savefilename)) { # || die "can't read $savefilename: $!";
					@lines = <IN>;
					close IN;
					$happywithcached = 1000;   # so we don't try parsing the header, etc.
				}
			}
		}
	}
	my $tmpdbgnum = 100;
	if (!$happywithcached) {
		if ($dontusecached) {
			dbgv("told not to use cached for $getdomain $file (params: $paramstring)");
			if (!$g_absolutelyneveroverwritecached) {
				dbgv("ERROR--event though g_absolutelyneveroverwritecached, still got dontusecached");
			}
		}
		elsif (-s $savefilename) {
			$cachetimeelapsed = 1;
			my $tmpct = (-M $savefilename);
			my $tmpmin = $tmpct * 24 * 60;
			dbgv("requesting from $getdomain $file (old)"); # age $tmpmin is greater than $g_cachetime......");
		}
		else {
			dbgv("requesting from $getdomain $file (no exist)");
		}
		my $reqfile = $file;
		if ($reqfile =~ /\/$/ && $paramstring) {
			dbgv("because $reqfile ends with slash and there is parameter, will remove /");
			$reqfile =~ s/\/$//;
		}
		my $sockret;
		# NOTE: socketrequest  has an alarm eval, so this must be outside the main alarm eval (which is mcuh longer)
		($sockret, @lines) = SocketRequest($getdomain, $port, "$reqfile$paramstring", $savefilename, $dontusecached); 
		$tmpdbgnum = @lines;
		# dbgv("finished with SocketRequest - got $tmpdbgnum lines");
		# if ($tmpdbgnum < 6) { dbgv("here they are:\n@lines"); }
		if (!$sockret) {
			if (-s $savefilename) {
				if (open(IN, $savefilename)) { # || die "can't read $savefilename: $!";
					dbgv("since couldn't connect to $getdomain for $file, using cached $savefilename instead");
					@lines = <IN>;
					close IN;
					$happywithcached = 2222;   # so we don't try parsing the header, etc.
					# note: a good thing to do would also be to touch the $savefilename so maybe next time
					#	don't wait for it...
					system("touch $savefilename");
				}
				else {
					dbg("returning from dealwtihfile; " .
						"unable to open socket for $file, couldn't open $savefilename either!");
					printtoscreen("Sorry, currently no $file is available. Please try later.") if $toscreen; 
					$errorcode = 727;
					return $errorcode;
				}
			}
			else {
				dbg("returning from dealwithfile; " .
					"unable to open socket for $file, $savefilename didn't exist either!");
				printtoscreen("Sorry, $file not currently available. Please return at a later time.") if $toscreen; 
				$errorcode = 747;
				return $errorcode;
			}
		}
	}

	# put main eval/alarm start here... so that can have a separate little one for the connect above
	$SIG{ALRM} = sub { die "timeout" }; 
	# in practical terms, this line tells the script to go to the "eval error foo"
	# if the alarm time expires. just leave it above the eval.
	eval {  # functional part of the code is in an eval for the alarm call.
		alarm($g_killtime) ; # this line actually sets the alarm for the eval. die if not done in this many seconds.
		if (!$happywithcached) {
			my $continueplease;
			if (!$g_dontuseHTTP10) { # not sure what to do about it besides this...
				# if ($tmpdbgnum < 6) { dbgv("here are the lines before ParseResponseHeader:\n@lines"); }
				($continueplease, $startoutline, $happywithcached, $errorcode) = ParseResponseHeader(\@lines, 
								$savefilename, $savefilenamepending, 
								"$getdomain$file", $subdomain, $toscreen, $dontusecached);
								# note: $getdomain$file is just for debugging
				# if ($tmpdbgnum < 6) { dbgv("here are the lines after ParseResponseHeader:\n@lines"); }
				if (!$continueplease) { 
					# important note: this return does not exit dealwithfile -- it exits the eval, i think...
					dbgvv("returning from eval in dealwithfile");
					return $errorcode;
				}
			}
		}
		if (!$startoutline) {
			# todo: figure this out--didn't we already find mimetype? hm...
			if($happywithcached) {
				$mimetype = mimefind($savefilename);
			} else {	
				$mimetype = mimefind($file);
			}
			$startoutline = "Content-type: $mimetype\n\n";
		}
		if (!$g_nomod || $g_stubtype eq "cgi") { # !$g_usephp) {
			if ($toscreen) {
				dbgv("printing $startoutline because toscreen");
				print $startoutline;
			}
		}
		if (!$happywithcached) {

			my $usenewfunction = 1;
			if ($usenewfunction) {
				($outfile, $savefilenamepending, $errorcode) = GetOutfile($savefilenamepending);
				dbgv("got $savefilenamepending from GetOutfile");
				if ($errorcode) { # nonsense message that sounds ok.
					print "<html><body>" .
						"Traffic on this server ($g_givemedomain) is exceptionally heavy right now. " .
						"Please try back later." .
						"</body></html>"
						if $toscreen;
					dbgv("returning from dealwithfile in eval for traffic message--errorcode $errorcode");
					return $errorcode;
				}
				dbgv("... and will begin writing");
				$beganwriting = 1;
			}
			else {
				# See http://www.perlmonks.org/index.pl?node_id=7058&lastnode_id=102 for file locking tutorial.
				$outfile = FileHandle->new();
				my $pendingfileexisted = (-s $savefilenamepending);
				if ($pendingfileexisted) {
					$outfile->open("+< $savefilenamepending") || dbg("ERROR: ".
							"couldn't open $savefilenamepending for read/write use: $@");
				}
				else {
					# if you only do this one in all cases--as before--then when the $savefilenamepending
					# is already being written, it will be truncated anyhow at that point--will show up
					# as a bunch of blank space.
					$outfile->open(">$savefilenamepending") || dbg("ERROR: ".
							"couldn't create file $savefilenamepending: $@");
				}
				$beganwriting = 1;
				chmod $g_permissions, $savefilenamepending; # ???? what's this for????
				unless (flock($outfile, 6)) { # LOCK_EX | LOCK_NB
					# flock($outfile, 8);
					# $outfile->close(); # should use cleanup(0,0,0,0) but have that function check for outfile...
						# which i guess should be a global sometimes...
					dbgv("CAN'T IMMEDIATELY WRITE-LOCK $savefilenamepending ($!), " .
						"so will sleep and then return to start of function, or something");
					$askedtolockpending++;
					if ($askedtolockpending > 1) {
						print "<html><body>" .
							"Traffic on this server ($g_givemedomain) is exceptionally busy right now. " .
							"Please try back later." .
							"</body></html>"
							if $toscreen;
						$errorcode = 505; # not the right code, but whatever
						dbgv("returning with traffic message, $errorcode");
						return $errorcode; # this does not return from the fn, just from the eval, i think
					}
					else {
						sleep 10;
						goto FAILEDTOLOCK;
					}
				}
				else {
					if ($pendingfileexisted) {
						dbgv("WAS ABLE TO GET IMMEDIATE WRITE-LOCK, ".
							"but since $savefilenamepending existed, now we will truncate it");
						seek($outfile, 0, 0); # go to end of file
						truncate($outfile, 0); # truncate file
					}
				}
			}
		}
		# if not cached then cache it, unless it's html, etc., which needs to get parsed.
		if(!$happywithcached && !$istobeparsed) {
			# dbgv("this is where we should be writing the lines to the outfile. here are the lines:\n@lines");
			print $outfile @lines;
		}
		# if it is cached, or it's not to be parsed, display as-is.
		if ($happywithcached || !$istobeparsed) {
			print @lines if $toscreen;
			flush(STDOUT) if $toscreen;
			# cleanup($beganwriting, $savefilenamepending, $savefilename, $outfile); # overwrite IF started writing...
			# return;
		} 
		else {  # or do parsing for subsitutions...
			# ParseSublines();
			ParseCheckdoms();
			my $withintag = 0;
			my $line;
			my $linesprocessed = 0;
			while ($line = shift @lines) {
				# convert unwieldy pc/mac newlines to unix...
				if (0) { # screws up binary files -- doc, pdf, etc. -- check for those first
					$line =~ s/\015\012?/\n/g;
				}
				my $origline = $line;
				if ($line =~ /^\s*$/) { # if all whitespace, don't do anything 
				}
				else { # process the line
					$linesprocessed++;
					if ($mimetype eq 'text/html') {
						if ($withintag && $line=~ />/) { # todo: this logic to be improved, all of it--split
								# into chunks, eventually
							$withintag = 0;
						}
						# todo: actually, could just check on <script -- any kind of script might as well be
						#	javascript as far as avoiding substitutions goes....
						# if (($line =~ /<script\s*language\s*=\s*[\"\']?JavaScript/i) || 
						#   ($line =~ /<script>/i)) {
						if ($line =~ /<script/i) {
							$isjavascript = 1;
						}
						if ($isjavascript && $line =~ /<\/script>/i) {
							$isjavascript = 0;
						}
						if ($line =~ /^(\s*[<][^<]*>\s*)+$/) { 
							# make a note of only-tag-start-tag-end lines
							# could also check for withintag and then not worry about begin or end...
							my $onlytags = 1; # not used right now
						}
					}

					if ($g_metadesc) {
						$line =~ s|<head>|<head>\n<meta NAME="Description" CONTENT="$g_metadesc">|i;
					}
					if ($g_metakeywords) {
						$line =~ s|<head>|<head>\n<meta NAME="KeyWords" CONTENT="$g_metakeywords">|i;
					}

					# Do body text substitutions
					if (($mimetype eq 'text/html') || 
							$isjavascriptfile || $isjavascript) { # includes css (isjavascriptfile)	
						if (($isjavascriptfile || $isjavascript) && 
								($mimetype ne 'text/html') && ($mimetype ne 'text/css')) {
							dbg("WARNING: is javascript file ($isjavascriptfile) or is javascript ".
								"($isjavascript) but mimetype isn't text ($mimetype)");
						}
						my $subdomainpath = GetPathForSubdomain($subdomain);
						if (!$savingdirname) { # it can also be passed to dealwithfile
							my $strip = $g_basepath;
							if ($g_cachedir) { $strip = "$strip/$g_cachedir"; }
							$savingdirname = GetFileDir($savefilename, $strip);
						}
						$line =~ s/\&\#072\;ttp\:/http\:/g; # weird special case:

						my $dousersubs = 0;
						if (!$isjavascriptfile && !$isjavascript) {
							$dousersubs = 1;
						}
						$line = DoMostSubs($line, $savingdirname, $subdomainpath, 
							$basepath, $markbasepath, $dousersubs, $mimetype);

						# fudges and fusses and fixes
						# todo: need to figure out how to put below into sub file
						$line =~ s/flash_installed=yes/flash_installed=no/g; # fussing-with (hk)
						# $line =~ s/useFlash == false/true/g; # fussing-with (bm)
						$line =~ s/useFlash = 1/useFlash = 0/g; # fussing-with (bm)
						$line =~ s|\"http\:\/\/\"\s*\+\s*location\.hostname\s*\+\s*||g; # fussing-with (dow)
						$line =~ s|\"http\:\/\/\"\s*\+\s*location\.host\s*\+\s*||g; # fussing-with (dow)
						$line =~ s|http\:\/\/\'\s*\+\s*location\.host\s*\+\s*\'||g; # fussing-with (dow)
						$line =~ s|\?cnn=yes||g; # hacky fussing-with (cnn)--see todo for fix

						if ($g_killflash) {
							$line =~ s/\.swf/\.garbage/g; # very heavy-handed! but sometimes necessary.
						}
					}
					if ($g_stealemails) {
						if ($g_myemail) {
							# to switch any e-mail address for $g_myemail !!
							# you might need to remove the ^ and $:
 							# /^\S+\@\S+\.[a-zA-Z]{2,3}$/
							# (from before: maybe below works... just added \\s in back of the thing)
							my $tagends = "\\<\\>\\:$g_startdelims"; # for "mailto:" etc.
							$line =~ 
							   # s|[^$tagends]*\@[^g_startdelims]*([$g_startdelims].*)?$|$g_myemail$1|g;
							   # s|[^$tagends]*\@[^g_startdelims]*|$g_myemail|g;
							   s|[^$tagends]*\@[^$g_startdelims]*<|$g_myemail<|g;
						}
						elsif ($g_mybaredomain) {
							# todo: make these better--make these just the last two globs
							#   e.g. in europa.eu.int, just eu.int 
							# and instead of @$myemaildomain, make it 
							#	@[any sequence of valid chars]$myemaildomain
							my $myemaildomain = $g_mybaredomain;
							# my $emaildomain = $g_givemebaredomain; # maybe leave that...
							foreach $barecheckdom (@g_barecheckdoms) {
								$line =~ s/\@$barecheckdom/\@$myemaildomain/g;
							}
							$line =~ s/\@$g_givemebaredomain/\@$myemaildomain/g;

						}
					}
					# below is hacky--instead, add to GrabRefs a thing for prefix--which will include http:
					if ($g_rewritefullurls) { # && $g_mydomain) { # hacky thing to get things we've missed...
						# my $adddir3 = $g_basedir; # if it exists, of course
						$line =~ s|http:\/\/$g_givemedomain|$g_basepath|g;
						$line =~ s|http:\/\/$g_givemebaredomain|$g_basepath|g;
						# $line =~ s/$g_givemedomain/$g_mydomain$adddir3/g; # then some sort of ftp thing
					}

					if (!$withintag && $origline =~ /.*<[^>]*$/) {
						$withintag = 1;
					}
				} # end of not-all-whitespace line check
				print $outfile $line; # try giving it an extra \r--for binary file consistency (doc, pdf, etc.)
				print $line if $toscreen;
				flush(STDOUT) if $toscreen;
			}
			dbgv("$linesprocessed lines were processed in $savefilename");

		} 
		# my $tmpsize = -s $savefilenamepending;
		# dbgv("going into cleanup on $savefilenamepending (size $tmpsize)") if $beganwriting;
		cleanup($beganwriting, $savefilenamepending, $savefilename, $outfile); # overwrite file IF began writing
		# dbgv("finished with cleanup");
	
		if ($pleasetoscreen && !$canbespewed) { # we have parsed and written the file to disk, but we haven't displayed it
			dbgv("was requested to show to screen, but couldn't be spewed (toscreen was: $toscreen)--" .
					"so redirecting now at end to $savefilename");
			if (!($g_stubtype =~ /php/)) {
	 			dbgv("WEIRD--how did get $g_stubtype thinking it couldn't be spewed???"); 
				# print "Location: $savefilename\n\n";
			}
			else {
				# we have to write a refresh thing
				my $output =  	"<html>\n<head>\n" .
						"<meta http-equiv='refresh' content='0; URL=$savefilename'>\n" .
						"</head>\n<body>\n</body></html>";
				print $output;
			}
		}
		
		alarm(0);	# this line just clears the alarm. it should stay right above the end of the eval.
				# so if you decide to move the end of the eval (i.e. the timed portion) then be sure
				# to move the alarm(0); line with it.
						
	}; # end eval

	#### eval error foo - i.e. what happens if the alarm kills it...
	#### leave it right after the end of the eval.
	if ($@) {
		if ($@ =~ /timeout/)  {
			# here's where it goes if the alarm expires.
			dbg("Timed out after trying for $g_killtime seconds on $file - cleaning up...");
			print "@lines\n" if $toscreen;	# causes remaining available text to be printed unparsed, rather than leave 
						# a partially blank page. if this creates too much munged html, get rid of this line. 
			cleanup(0, 0, 0, 0); # don't finalize file or anything
			alarm 0;			# clear the alarm
		}
		else {
			# propagate unexpected exception - in other words, it crashed.
			dbg ("Uh oh, trouble:  $@"); 
			alarm 0 ;        # clear the stillpending alarm
			die;

		}
	} # end if $@
	#### end eval error foo

	$g_dbgtabs = $g_dbgtabs - 1;
	dbgvv("returning from dealwithfile at end");
	return $errorcode;
} # end of giant dealwithfile routine

####################### subroutines #############################
# have gone through subroutines and removed any dependences on global variables other than those prefixed with g_

sub cleanup {
	# no dependences on savefilename or savefilenamepending any longer
	my($finalizefile, $savefilenamepending, $savefilename, $outfile) = @_;
	# if (S) {
		# close(S); # this shouldn't be necessary any longer--it's only kept open during socketrequest
	# }
	# if (OUT) {
	#	close(OUT);
	# }
	if ($finalizefile) { # ($beganwriting && !$timingout) { # can pass just a "finalize the file" variable
		# dbgv("have called cleanup with $finalizefile, $savefilenamepending, $savefilename, and an outfile handle");
		if (!$savefilenamepending || !$savefilename) {
			dbg("ERROR: in cleanup, finalize but no savefilename ($savefilename) or savefilenamepending($savefilenamepending)");
		}
		$outfile->close(); 
		if (move($savefilenamepending, $savefilename)) {
		# if (copy($savefilenamepending, $savefilename)) { # for debug
			# test: check whether it moved--only do below if it in fact moved it
			chmod $g_permissions, $savefilename;    # probably unnecessary; 
								# changed from 666 to 777 to avoid dir errors even now
			if (-s $savefilename == 0) { 
				dbg("WACKY!! somehow, $savefilename is blank during cleanup--therefore unlinking it.");
				unlink $savefilename;
			}
		}
		else {
			dbgv("failed to move $savefilenamepending onto $savefilename: $!");
		}
	}
}

sub checkdbgfilesizeifnecessary {
	if (!$g_dbgfilesizechecked) {
		dbg("dbgfilesizelimit = $g_dbgfilesizelimit");
		if ($g_dbgfile && $g_dbgfilesizelimit > 0) {
			$dbgfilesize = -s $g_dbgfile;
			dbg("dbgfilesize = $dbgfilesize");
			if ($dbgfilesize > $g_dbgfilesizelimit) {
				dbgv( " - backing up dbgfile $g_dbgfile, it is bigger than $g_dbgfilesizelimit" );
				if ($g_dbgfh) { close($g_dbgfh); }
				system("mv $g_dbgfile $g_dbgfile.bak"); # could replace with native move
				# todo: keep more files--make number of dbg files a variable (or -1 for all)
				if ($g_dbgfh) { open($g_dbgfh,">>$g_dbgfile") || print "can't open $g_dbgfile $!\n"; }
			}
		}
		$g_dbgfilesizechecked = 1;
	}
}
sub dbgvv {
	my($msg) = @_;
	dbg($msg) if ($g_dbgveryverbose);
}
sub dbgv {
	my($msg) = @_;
	dbg($msg) if ($g_dbgverbose);
}
sub checkopendbgfile {
	if (!$g_dbgfile && $g_dbgfileraw && $g_basepath) {
		$g_dbgfile = $g_dbgfileraw;
		if (!$g_nomod) { # && !($g_dbgfile =~ /^\/?$g_cachedir/)) {
			$g_dbgfile = "$g_cachedir_mod_rewrite/$g_dbgfile";
		}
		else {
			if ($g_cachedir) {
				$g_dbgfile = "$g_cachedir/$g_dbgfile";
			}
		}
		$g_dbgfile = "$g_basepath/$g_dbgfile";
	}
	if (!$g_dbgfh && $g_dbgfile) {
		$g_dbgfh = FileHandle->new();
		open($g_dbgfh,">>$g_dbgfile") || warn "can't open $g_dbgfile $!\n";
		seek($g_dbgfh,0,2); # don't bother locking
		return 1;
	}
	else {
		return 0;
	}
}
sub dbg { 
	my($msg) = @_;
	checkopendbgfile();
	my $tabs = "";
	my $numtabs = $g_dbgtabs;
	while ($numtabs > 0) {
		$tabs = "$tabs\t";
		$numtabs--;
	}
	my $startbit = "$tabs";
	if ($g_remoteaddr) { $startbit .= "$g_remoteaddr"; }
	$startbit .= " [$$]";
	$startbit .= scalar(localtime); 
	print $g_dbgfh "$startbit:\n$tabs   $msg\n" if $g_dbgfile;
	flush($g_dbgfh);
}

sub getaddress {
	my($host) = @_;
	my(@ary);
	@ary = gethostbyname($host);
	return(unpack("C4",$ary[4]));
}

sub mysub { 
	my($line, $subfrommysub, $subtomysub, $subparamsmysub) = @_;
	if ($subparamsmysub =~ /i/) {
		$line =~ s|$subfrommysub|$subtomysub|ig;
	}
	else {
		$line =~ s|$subfrommysub|$subtomysub|g;
	}
	return $line;
}

sub SplitURL { # ok, doesn't depend on globals
	my($fullurl, $strict) = @_;
	# dbgv("received $fullurl, with strictness $strict");
	$fullurl =~ s/\n+//;
	$fullurl =~ s/\r+//;
	$fullurl=~ s|([^:]+)://||;		# lose the beginning http:// type crap
	my $theprotocol = $1;
	$fullurl =~ s|/$||;			# lose the trailing /
	my($thehost) = $fullurl;
	my($thefile) = $fullurl;
	# dbgv("at this point the protocol is $theprotocol");
	if (!$strict || $theprotocol) {
		$thehost =~ s|(^[^\/]*).*|$1|;		#lose everything after the domain slash
		$thefile =~  s|^[^\/]*(.*)|$1|;		#lose everything before the domain slash
	}
	else {
		dbgv("since strict, and no protocol, will set host to 0 and file to $thefile");
		$thehost = 0; # can't tell, it's just a path
	}
	if (0) { # old clumsy way of doing it
		@dparts = split(/\//, $fullurl); 
		# $thehost is what is before the first /
		$thehost = shift(@dparts);
		$thehost =~ s|^http://||i;
	 
		$thefile = "/";
		while (defined($bit = shift(@dparts))) {
			$thefile = "$thefile$bit";
		}
	}
	return ($thehost, $thefile, $theprotocol);
}
$g_didntparse = [0, 0, 0]; 
sub ParseOneSubline {
	my($subline) = @_;
	my $break = "\t";
	my($subfrom);
	my($subto);
	my($subparams);
	my $startswithtab = 0; # now is "my"
	chomp($subline);
	if ($subline =~ /^\s*#/) { 
		return 0; 
	}
	if ($subline =~ /^\s*$/) { 
		return 0; 
	}
	if (!($subline=~ /$break/) && !$g_fluffmode) { 
		dbgv("line has no tab and won't be used: $subline");
		return 0;
	 }
	$subline =~ s/\t\t/\t/g;
	$subline =~ s/\t\t/\t/g;
	$subline =~ s/\t\t/\t/g;
	$subline =~ s/\t\t/\t/g;
	$subline =~ s/\t\t/\t/g;
	$subline =~ s/\n//g;
	$subline =~ s/\r//g;
	if ($subline =~ /^\t/) {
		$startswithtab = 1;
		$subline =~ s/\t//; # should just get rid of first one
	}
	my @sublineparts = split(/\t/, $subline); # now is "my"
	if (!defined($subfrom = shift(@sublineparts))) {
		dbg( "ERROR: no subfrom in line: $subline" ); return $g_didntparse;
	}
	if ($subfrom =~ /^$/) {
		dbg( "ERROR: blank subfrom in $subline" ); return $g_didntparse;
	}
	if (!$g_fluffmode) {
		if (!defined($subto = shift(@sublineparts))) {
			dbg( "ERROR: no subto in line: $subline" ); return $g_didntparse;
		}
		if ($subto =~ /^$/) {
			dbg( "ERROR: blank subto in $subline" ); return $g_didntparse;
		}
	}
	else {
		$subto = "-";
	}
	if (!defined($subparams = shift(@sublineparts))) {
		$subparams = "";
	}
	my($moreshit);
	if (defined($moreshit = shift(@sublineparts))) {
		dbg( "ERROR: extra shit $moreshit at end of $subline" ); return $g_didntparse;
	}
	
	return ($subfrom, $subto, $subparams, $startswithtab);
}

# todo: to fix up substitute function,
# might be good to make test target website with
# nation asdfasdfasdfa asdfasdfa
# nation <a href=asdfasdfasdf>asdf</a>
# asdfasdfasd nation asdfasdfasdfasdf
# asdfasdfasd national asdfasdfasdfasdf
# asdfasdf donation asdflaksdjfasdf
# asdfas <a href="asdf">donation</a>
# asdfas <a href="asdf">nation</a>
# asdfas <a href="asdf">national</a>
# and see, with nation -> frontier, what it works as expected on and what it doesn't

# NOTE: see malfunction note for $b1

sub substitute {
	my($line, $subfrom, $subto, $ignorecase) = @_;
	dbgvv("entered substitute with $subfrom, $subto, $ignorecase, to apply to:\n\t$line");
	my $dbgtmp = 0;
	my ($b1, $b2, $b);
	
	$b1 = 	'\w*(?![\.\/])\W'; # doesn't match on linestart: ^from -> ^from : INCORRECT
	$b2 = 	'((?![\.\/])[\W])|(\.\s)|(\.$)'; # this one seems to work ok, as far as i can tell

	if (!($line =~ />/) && !($line =~ /</)) { # no tags to watch out for
		if ($ignorecase) {
			while ($line =~ s/($b1)($subfrom)($b2)/&smartcaps($2,$subto,$1,$3)/eig) {
				if ($dbgtmp) { dbgv("found 3 $subfrom ---> $subto ($line)") if $dbgtmp; }
			}
		}
		else {
			while ($line =~ s/($b1)$subfrom($b2)/$1$subto$2/g) {
				if ($dbgtmp) { dbgv("found 4 $subfrom ---> $subto ($line)") if $dbgtmp; }
			}
		}
	}
	else { 	# idea here is to make sure that nothing within a tag is replaced, so:
		# name="country"><tr> 				-> 	unchanged
		# <asdfas><asdfasdf><thing=a country thing 	-> 	unchanged
		# <asdfasdf>asdflkja country <odas> 		-> 	<asdfasdf>asdflkja unit <odas>
		my $before = '.*>[^<]*';
		my $after = '[^>]*<.*';
		if ($ignorecase) {
			# todo: for the C.A. problem -- try (just for the hell of it) getting rid of the \b for that...
			while ($line =~ s/($before)\b($subfrom)\b/&smartcaps($2,$subto,$1,"")/eig) {
				if ($dbgtmp) { dbgv("found A $subfrom ---> $subto ($line)") if $dbgtmp; }
			}
			while ($line =~ s/\b($subfrom)\b($after)/&smartcaps($1,$subto,"",$2)/eig) {
				if ($dbgtmp) { dbgv("found B $subfrom ---> $subto ($line) ") if $dbgtmp; }
			}
		}
		else {
			while ($line =~ s/($before)\b$subfrom\b/\1$subto/g) {
				if ($dbgtmp) { dbgv("found C $subfrom ---> $subto ($line)") if $dbgtmp; }
			}
			while ($line =~ s/\b$subfrom\b($after)/$subto\1/g) {
				if ($dbgtmp) { dbgv("found D $subfrom ---> $subto ($line)") if $dbgtmp; }
			}
		}
	}
	dbgvv("returning from substitute");
	return $line;
}

sub smartcaps {
        my ($old, $new, $preceding, $trailing) = @_; 
	my ($ret);
	
        if ($old =~ /^[A-Z]+$/) { 
		$ret = uc($new); 
	}
        # elsif ($old =~ /^[A-Z][a-z]+.*$/ || $old =~ /^[A-Z]\..*$/) { 
        elsif ($old =~ /^[A-Z].*$/ || $old =~ /^[A-Z]\..*$/) { 
		$ret = ucfirst($new); 
	}
	else { 
		$ret = lc($new); 
	}
	$ret = "$preceding$ret$trailing";
        return $ret;
}
sub GetForms { # i think it doesn't use any globals
	my($raw) = @_;
	# assume singular
	my($singular) = $raw;
	my($root);
	my($plural);
	my($past);
	my($y_end) = 0;
	my($s_end) = 0;
	$root = $raw;
	if ($raw =~ /y$/) {
		if (!($raw =~ /[aeou]y$/)) {
			$y_end = 1;
			$root =~ s/y$//;
		}
	}
	elsif ($raw=~ /s$/) {
		$s_end = 1;
	}
	if ($y_end) {
		$plural = $root . "ies";
	}
	elsif ($s_end) {
		$plural = $root . "es";
	}
	else {
		$plural = $root . "s";
	}
	if ($y_end) {
		$past = $root . "ied";
	}
	else {
		$past = $root . "ed";
	}
	return ($root, $singular, $plural, $past);
}

sub SocketConnect { # todo -- MIGHT need to make S not global... though looks like it's only used in socketRequest... if so, ok.
	my($getdomain, $port) = @_;
	my($sockaddr,$there,$response,$tries) = ("Snc4x8");
	my $there = pack($sockaddr,2,$port, &getaddress($getdomain));
	my($a, $b, $c, $d) = unpack('C4', $hostaddr); # OOPS--hostaddr is never anything!

	my $proto = (getprotobyname ('tcp'))[2];
	my $numtotry = $g_socketconnecttime; # in seconds
	$SIG{ALRM} = sub { die "connect timeout thing" };
	eval {
		alarm($numtotry); # in seconds
        
		# connect code here
		if (!socket(S,AF_INET,SOCK_STREAM,$proto)) { 
			dbg( "oops dead socket 1: $!" ); 
			return 0;
			# die "$0:  Fatal Error.  $!\n"; 
		}
		if (!connect(S,$there)) { 
			dbg( "oops dead socket 2: $!" );
			return 0;
			# die "$0:  Fatal Error.  $!\n"; 
		}
        
		alarm(0);
	};
	if ($@) {
		# i guess now it's returned 0 already in that sub { return 0 } thing??? i think i don't understand...
		dbgv("since didn't connect within $numtotry seconds, returning");
		alarm 0;			# clear the alarm
		return 0;
	}

	select(S);
	$|=1;
	select(STDOUT);
	return 1;
}

# this sends the actual HTTP request.
sub SocketRequest {
	my($getdomain,$port,$file, $savefilename, $dontusecached) = @_;
	my @response;
	my $ret = 0;

	if (SocketConnect($getdomain,$port)) { # || die "no connection!";
		$ret = 1;
		if (!$savefilename) {
			dbg("ERROR: blank savefilename");
		}	
		# todo: make S local... is it possible to return it from SocketConnect????
		#    answer: yes, with FileHandle (i think)
		if (!$g_dontuseHTTP10) {
			print S "GET $file HTTP/1.0\r\n";
			if (!$dontusecached && (-f $savefilename)) { # if cached file exists, check time, send If-Modified-Since
				my $compare = statfiletime($savefilename);
				my $ifmodline = "If-Modified-Since: $compare";  # seems to be touchy header... keep here, don't move
				print S "$ifmodline\r\n";  # seems to be a touchy header... keep it up here, don't move it.
			}
			print S "User-Agent: Mozilla 4.2\r\n"; 
			print S "Referer: $g_referer\r\n"; 
			print S "Host: $getdomain\r\n";
			# print S "Connection: Keep-Alive\r\n";  # don't use this!
			print S "\r\n";
		}
		else {
			print S "GET $file\r\n";
		}
		@response = <S>;
		close S;
	}
	return ($ret, @response);
}

sub statfiletime { 
	# sub to get the time of an existing file and return 
	# it in GMT in proper HTTP header order
	my($whatfile) = 	@_;
	my $mtime = (stat $whatfile) [9];
	my $gmval = gmtime($mtime);
	my @datevals = split ('\s', $gmval);  #gmtime is different in scalar and array context
	my $httptime = join (" ", "$datevals[0]\,", "$datevals[2]", "$datevals[1]", "$datevals[4]", "$datevals[3]", "GMT");
	return $httptime;
}		 

sub makemimehash () {
	# sub to create a global hash "%mime" which contains the extension/mime-type pairs from the mime.types file.
	my $mimefile = "$g_basepath/mime.types\n";
	$g_mimefilefound = 0; # can be global, that's fine
	$g_mademimehash = 1; # whether or not it worked
	my $line;
	if (!open(MF, "$mimefile")) {
		my $miss = "$mimefile file is missing!";
		warn "$miss\n";
		dbg($miss);
	}
	else {
		$g_mimefilefound = 1;

		while ($line = <MF>) {
			chomp $line;
			if (($line =~ /^#/) || ($line =~ /^\s+$/)) { 	# ignore comments and blank lines
				next;
			}	 
			my @fields = split ("\t+", $line);
			my @subfields = split (" ", $fields[1]); # this line handles multiple extensions for a mime-type
			my $member;
			foreach $member (@subfields) {
				$g_mime{$member} = $fields[0]; # keys are exts.. values are mime-types	
				# note: there can be multiple keys (exts) for each value (mime-type).
			}	
		}
		close MF;
	}
}		


sub mimefind () {
	# sub to look up the mime-types in the %mime hash
	my ($filename) = @_;
	if (!$g_mademimehash) {
		makemimehash();
	}
	if ($g_mimefilefound > 0) {
		my $ext = (fileparse($filename,'\.[^.]*'))[2];
		$ext =~ s/^\.//;
		my $mimetype = $g_mime{$ext};
		if (!$mimetype) {
			$mimetype = "text/html"; # this actually works for everything...
			# dbg("no mimetype for $filename so defaulting to $mimetype");
		}
		return $mimetype;
	}
	return 0;
}	
	
sub makedirectories {	
	my ($realpath) = @_;
	my @sfndirparts = split(/\//, $realpath); 
	my($sfndirbit);
	my $pathsofar = 0;
	while (defined($sfndirbit = shift(@sfndirparts))) {
		   if ($pathsofar) {
			   if ($pathsofar ne "") {
				   unless (-d $pathsofar) {
						my $temppath = $pathsofar;
						$temppath =~ s|/$||; # OSX/NetBSD don't like trailing / when mkdir-ing
						mkdir $temppath, $g_permissions;
						chmod $g_permissions, $temppath;
				   }
			   }
		   }
		   else {
			   $pathsofar = "";
		   }
		   $pathsofar = "$pathsofar$sfndirbit/";
	}
}

sub dadasubcaller {
	# sub to call dadasub and prepend or append tags from line
	# It gets called by FluffWork.
	
	my ($dada, $parseme, $tagstuff, $beforeorafter) = @_;
	# @ fluffwords will be defined in calling routine as a local variable.
	# only because i get confused when passing arrays vs. refs to arrays
	dbgv ("DADASUBCALLER: will parse $parseme, tags are $tagstuff and before-after is $beforeorafter");
	my $donedada =  &dadasub($dada,$parseme, @fluffwords);
	if ($beforeorafter eq 'before') {
		$output = "$tagstuff $donedada";
	}
	else {
		# $output = "$tagstuff $othertext"; sleepy booboo?
		$output = "$donedada $tagstuff";
	}
	dbgv ("DADASUBCALLER: returning $output");
	return $output;
}			
	
sub FluffWork {
	my ($line) = @_;
	my %assocarray = @g_flufflines;
	# dbgv("g_flufflines = @g_flufflines");
	local @fluffwords = keys(%assocarray);
	my $dadaline;
	my $dada = "....."; # todo - put in the conf file.
	my $dbgtmp = 1;
	
	if (!($line =~ />/) && !($line =~ /</)) { # no tags in line.
		
		$dadaline = dadasub ($dada, $line, @fluffwords);
		dbgv ("NO TAGS - returning DADALINE $dadaline without dadasubcaller");
	}
	
	# next part is copied from substitute()
	else { 	# idea here is to make sure that nothing within a tag is replaced, so:
		# name="country"><tr> 				-> 	unchanged
		# <asdfas><asdfasdf><thing=a country thing 	-> 	unchanged
		# <asdfasdf>asdflkja country <odas> 		-> 	<asdfasdf>asdflkja unit <odas>
		
		# cue p.'s experimental use of non-greedy quantifiers here, as well as paren
		# expression for purposes of hitting &nbsp;
		my $nbsptag = '\b&\w+\;\b*'; #just for explanation purposes, not currently used.
	
		# also not working - these tags are what codemonkey was using, except non-greedy.
		# my $before = '.*?>[^<]*?';
		# my $after = '[^>]*?<.*?';
		
		# these lines attempt to put $nbsptag into the matched tag pattern. still grabbing & though.
		# CODEMONKEY - HELP!
		
		my $before = '.*?>(:?\b&\w+\;\b)*[^<&]*?';
		my $after = '[^>&]*?(:?\b&\w+\;\b)*<.*?';
		
		my $subbed;

	
		if ($line =~ s/($before)(\b[^<>]+\b)+/dadasubcaller($dada, $2, $1, "before")/eig) {
			$subbed = 1;
			$dadaline = $line;
			if ($dbgtmp) { dbgv("dadasubbed FOUND A"); }
			
		}
		if ($line =~ s/(\b[^<>]+\b)+($after)/dadasubcaller($dada,$1,$2, "after")/eig) {
			$subbed = 1;
			$dadaline = $line;
			if ($dbgtmp) { dbgv("dadasubbed FOUND B"); }
		}
		
		if (!$subbed) {
			dbgv("FLUFFWORK: line must be all tags. LINE IS: $line\n");
			$dadaline = $line;
		}	
			
		### 	 	
	
	}	

	# flufftodo:
	# What you need to do is consider two situations:
	#
	# 1.
	# if ((!($line =~ />/) && !($line =~ /</)) {
	# In this case you know you've just got interesting text, because you know you're not in javascript if you've
	# gotten to this function. And you *should* know that you're not $withintag (but I think that's not working right
	# now, I just noticed).
	# So in theory you can just split the text into words.
	#
	# 2.
	# otherwise.
	# Here it's more complicated--you have to check and make sure that you're only getting stuff in-between > and <.
	# so for example
	# asdlfkjaosdiuf alsdkfj <asdf>oiusdf<asldkfjasdfl kdslfaksjdf>soidufoiuwer alsdkjfasd falskdfj <asldkfjasldfkjasdf=
	# and
	# asldfkjalsdfkjasdloiu alsdkjf> asldkfj sdkjfsdfkl <asdlfkasdf skdfjsdf>
	# and
	# asldfkajsdf> alsdkfasdf <asldfkjasldf
	# and so on have to be considered--you don't want to touch what's in-between the < and >
	# I do this in substitute { function, where there's $before and $after, and each sub checks on these. You have to
	# check the words that are between these, somehow, using same logic as in those $before and $after regexes.
	# 
	# To see if a particular word is to be kept, you just take it ($thisword), 
	# put it in lowercase ($lowercaseofthisword), and then:
	# $istobekept = $assocarray{$lowercaseofthisword};
	# (note: for this to work, each element of @g_flufflines should be in lower case)
	#
	# Oops, just looked in your dadasub, i see the grep syntax, I didn't know it, sounds better. So I guess
	# you want to make the @g_flufflines into *not* an associative array once you've filled it up... or maybe
	# it never has to be one...
	#
	# Anyhow, if crawling along the line is difficult, then another way to do it is mark each thing with a unique 
	# mark, store it in an array, and then replace the unique mark with the thing.... as I did in GrabRefs....
	# But maybe there's an easier way.

	return $dadaline;
}




sub dadasub {
    # subroutine that turns non-interesting words into a user-specified meaningless pattern.
    # to be used in $g_fluffmode.
	 
	# $pattern is the dada - "....." or whatever meaningless pattern user chooses. read from fluffwords.txt
	# $line is a line of text from the webpage.
	# @matchwords is a list of the fluffy words you'd match, which would be read from fluffwords.txt
	 
    my ($pattern, $line, @matchwords) = @_; 
    my $newline = "";
    my @line = split('\s',$line);
    dbgv("DADASUB input line is $line");
    WORDINLINE: foreach  $word (@line) {
    # in here goes the stuff to disqualify between tags
    # ok, seems to already have dealt with plurals etc. once it gets here.

    		local $grepword = $word;
    		$grepword =~ s/\W*$//;        # allow us to grep for word regardless of trailing punctuation...
		$grepword = lc $grepword;
		chomp($grepword);
			
			# check each word in the matchword list to see if it matches any.
	
			foreach  $matchword (@matchwords) {
				# todo - is codemonkey's way faster since it uses a hash?
				# dbgv("grepword is $grepword and matchword is $matchword");
				if ($grepword eq $matchword) { 
    		
         				$word = "$word ";      # it's a fluffword - put spaces around it and put it back in the line.
					$newline = "$newline" . "$word"; 
					next WORDINLINE;	
				}
				
    		}
			
	 		# or else, it didn't match any... 
        	$newline = "$newline" . "$pattern"; # replace with dada and reassemble the line.
    }

	 dbgv ("NEWLINE is $newline");
    return $newline;
}   # end dadasub











# this is just for use in text--not called if javascript
sub UserSpecifiedSubstitutions {
	my ($line, $strict) = @_;
	dbgvv("entered userspecifiedsubstitutions");
	my @arraytodo = @g_sublines;
	my ($sublineprocessed);
	foreach $sublineprocessed(@arraytodo) { 
		if ($sublineprocessed == 1) {
			# dbgv("skipping line in sub array because it is 1"); # the "value" in the associative array
			next;
		}
		my ($subfrom, $subto, $subparams, $startswithtab) = split(/\t/, $sublineprocessed); 

		if ($subparams =~ /t/) { 
			if ($line =~ /$subfrom/) {
				$line = $subto;
			}
		}
		# elsif ($subparams =~ /a/) {
			# $line =~ s/$subfrom/$subto/g;
		# }
		else {
			my $percnum = 0;	
			if ($subparams =~ /.*p(\d+).*/) {
				$percnum = $subparams;
				$percnum =~ s/.*p(\d+).*/$1/;
			}
			my $goahead = 1;
			my ($wentahead); 
			# if subfrom starts with a tab, group it with the previous one
			if ($startswithtab) {
				dbgv("subline (from $subfrom) starts with tab, so will group...");
				$goahead = $wentahead; 
			}
			if (($percnum > 0) && ($goahead > 0)) {
				my $randnum = rand(100);
				if ($randnum > $percnum) {
					$goahead = 0;
				}
			}
			if ($goahead) {
				my $ignorecase = 1;
				if ($subparams =~ /c/) {
					$ignorecase = 0;
				}
				my $dontworryabouttags = 0;
				my $nosmartsubstitutions = 0;
				my $smartsubsforsure = 0;
				my $notjustonwordboundaries = 0;
				if ($subparams =~ /h/) {
					$dontworryabouttags = 1;
				}
				if ($subparams =~ /d/) {
					$nosmartsubstitutions = 1;
				}
				if ($subparams =~ /s/) {
					$smartsubsforsure = 1;
				}
				if ($subparams =~ /a/) {
					dbgv("Oop--got notjustonwordboundaries, that's weird....");
					$notjustonwordboundaries = 1;
				}
				my $dosmartsubs = 0;
				if ($g_smartsubstitutions && !$nosmartsubstitutions && !$dontworryabouttags) {
					# todo: no $dontworryabouttags anymore... eliminate...
					$dosmartsubs = 1;
				}
				if ($smartsubforsure) {
					$dosmartsubs = 1;
				}
				if ($dosmartsubs) {
					# do a preliminary check for the wordroot -- if is in there, then 
					# go ahead and check for the rest
					if ($dontworryabouttags) { 
						dbg("ERROR--in dosmartsubs with dontworry");
					}
					my ($subfromroot, $subfromsingular, $subfromplural, $subfrompast) = 
						GetForms($subfrom);
					if ($line =~ /$subfromroot/i) { # is this working????
						my ($subtoroot, $subtosingular, $subtoplural, $subtopast) =
								GetForms($subto);
						$line = substitute($line, $subfromplural, $subtoplural, 
							$ignorecase, $dontworryabouttags, $strict, 
							$notjustonwordboundaries);
						$line = substitute($line, $subfrompast, $subtopast, 
							$ignorecase, $dontworryabouttags, $strict,
							$notjustonwordboundaries);
						$line = substitute($line, $subfromsingular, $subtosingular, 
							$ignorecase, $dontworryabouttags, $strict,
							$notjustonwordboundaries);

						if ($subto =~ /^[aeiou]/i) {
							$line =~ s/\b(a) $subtoroot/&smartcaps("$1", "an", "", " $subtoroot")/eig;
						}
						else {
							$line =~ s/\b(an) $subtoroot/&smartcaps("$1", "a", "", " $subtoroot")/eig;
						}

					}
				}
				else {
					$line = substitute($line, $subfrom, $subto, 
							$ignorecase, $dontworryabouttags, $strict,
							$notjustonwordboundaries);
				}
			}
			$wentahead = $goahead;
		}
	}
	dbgvv("returning from userspecifiedsubstitutions");
	return $line;
}
sub ParseSublines {
	if (!$g_sublinesparsed) { 
		dbgvv("about to parsesublines");
		my @sublists;
		@sublists = GetSubListNames($g_basepath);
		my $sublist;
		my @allsublinesraw;
		foreach $sublist(@sublists) {
			open(SUBLIST, "$sublist") || dbg("ERROR: couldn't open $sublist");
			# dbgv("parsing through sublist $sublist");
			my @sublinesraw = <SUBLIST>;
			close(SUBLIST);
			fixsublisttime($sublist); # checks to make sure is not in future
			push(@allsublinesraw, @sublinesraw);
		}
		my ($tline);
		foreach $tline(@allsublinesraw) {
			my ($subf, $subt, $subp, $startswitht) = ParseOneSubline($tline);
			if ($subf) {
				if ($subt =~ /\b$subf\b/) {
					# if so, just make the two lines manually.... sub a marker...
					my $markthing = "x#892BBB2893#.xiu8oiwern";
					dbg("in subs, \"$subf\" contained in \"$subt\"; splitting into two");
					addtosublines($subf, $markthing, $subp, $startswitht);
					addtosublines($markthing, $subt, $subp, $startswitht);
				}
				else {
					addtosublines($subf, $subt, $subp, $startswitht);
				}
			}
		}
		my $numentries = @g_sublines / 2;
		dbgv("$numentries substitutions (all told) to do on each line");
		# @g_sublines = sort @g_sublines;
		
		if ($g_fluffmode) {
			# now you probably want to take @g_sublines and make a simpler list @g_flufflines, right?
			# for each one, if smartsubs, then get the variants of $subf and put it in @g_flufflines
			# perhaps forget about the whole case-sensitive aspect, for the moment? make it always case-insensitive
			@g_flufflines = ( );
			my $fluffline;
			foreach $fluffline(@g_sublines) {
				if ($fluffline == 1) {
					# dbgv("skipping line in sub array because it is 1"); # the "value" in the associative array
					next;
				}
				my ($subfrom, $subto, $subparams, $startswithtab) = split(/\t/, $fluffline); 
				if ($subto ne "-") {
					# option has been added to ParseOneSubline so that if $g_fluffmode, it parses differently
					dbg("2: ERROR!!!!! subt should be - in fluffmode, instead it's $subto");
				} 
				my $dontworryabouttags = 0;
				my $nosmartsubstitutions = 0;
				my $smartsubsforsure = 0;
				if ($subparams =~ /h/) {
					$dontworryabouttags = 1;
				}
				if ($subparams =~ /d/) {
					$nosmartsubstitutions = 1;
				}
				if ($subparams =~ /s/) {
					$smartsubsforsure = 1;
				}
				my $dosmartsubs = 0;
				if ($g_smartsubstitutions && !$nosmartsubstitutions && !$dontworryabouttags) {
					# todo: no $dontworryabouttags anymore... eliminate...
					$dosmartsubs = 1;
				}
				if ($smartsubforsure) {
					$dosmartsubs = 1;
				}
				my @checktoadd = ( );
				if ($dosmartsubs) {
					my ($subfromroot, $subfromsingular, $subfromplural, $subfrompast) = 
						GetForms($subfrom);
					push(@checktoadd, $subfromsingular, $subfromplural, $subfrompast);
				}
				else {
					dbgv("adding $subfrom only to flufflines");
					push(@checktoadd, $subfrom);
				}
				# making this an associative array so can compare value more easily--not
				# just here when adding, but when checking each word against it....
				my %assocarray = @g_flufflines;
				my $add;
				foreach $add (@checktoadd) {
					my $val = $assocarray{$add};
					if (!$val) { # is there a better grep syntax way to do this?
						# flufftodo: for checking later, probably want
						# 	to put $add in lower case first
						push(@g_flufflines, $add, 1);
					}
				}
			}
		}
		$g_sublinesparsed = 1;
		dbgvv("finished parsesublines");
	}
}

sub addtosublines {
	my ($subf, $subt, $subp, $startswitht) = @_;
	my $sublineproc = "$subf\t$subt\t$subp\t$startswitht";
	if ($g_fluffmode && ($subt ne "-")) {
		dbg("1: ERROR!!!!! subt should be - in fluffmode, instead it's $subt ".
				"(subf $subf, subp $subp, line)"); # $tline)");
		exit(0);
	} 
	# not necessarily todo (will hurt the percentage thing i think):
	#	to speed this up (but take up a bit more memory), do the parsing here instead for
	#	the smartsubs (sing, plural, etc.) and add each one into the list

	# here, get any $matchurl thing--put into @g_matchurls where if the 
	# one element matches the $matchurl (partially), the other element is what to change it to
	if ($subp eq "u") {
		dbgv("got a u, adding $subf and $subt to g_matchurls");
		push(@g_matchurls, $subf, $subt);
	}
	else {
		# if you don't find $sublineproc in @g_sublines, add it now
		my %assocarray = @g_sublines;
		my $val = $assocarray{$sublineproc}; # NOTE: this was sublinecproc (typo)--that's 
							# why it wasn't working....
		if (!$val) {	
			push(@g_sublines, $sublineproc, 1); # put 1 so associative array
		}
		else {
			dbg("NOTE: line occurs more than once in sub files--fix:\n\t$sublineproc");
		}
	}
}

sub ParseCheckdoms {
	if (!$g_checkdomsparsed) {
		@g_checkdoms = split(",", "$g_givemealsogreedy");
		# now add the minus-www version of the givemedomain
	
		my @checkdomsspecific = split(",", "$g_givemealsospecific"); 
		foreach $checkdomspecific(@checkdomsspecific) {
			$specifictopush = "s:$checkdomspecific";
			push(@g_checkdoms, $specifictopush);
		}
		
		my $barecheckdom;
		foreach $barecheckdom (@g_checkdoms) {
			$barecheckdom =~ s/^s://i;
			$barecheckdom =~ s/^\s*(.*)\s*$/\1/; # no spaces
			$barecheckdom =~ s/^www\.//i;
			# dbgv("putting into g_barecheckdoms the thing $barecheckdom");
			push(@g_barecheckdoms, $barecheckdom);
		}

		$g_checkdomsparsed = 1;
	}
}
sub ParseResponseHeader { # only for HTTP 1.0, i think...
	my ($lines, $savefilename, $savefilenamepending, $requestmade, $subdomain, $toscreen, $dontusecached) = @_;
	my $continueplease = 1;
	my $startoutline = 0;
	my $happywithcached = 0;
	my $errorcode = 0;
	while($line = shift @$lines) {
		last if ($line =~ /^\n|^\r/);
		my $readfromcached = 0;
		if ($line =~ /Last-modified/i) {
			if (!$dontusecached && -f $savefilename) {
				my $lmline = $line;
				chomp($lmline);
				my @lmvals = split('\s', $lmline);
				my $mday = $lmvals[2];
				my $year = $lmvals[4];
				%g_months = (	Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, 
						Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11 );
				my $mon = $g_months{$lmvals[3]};

				my $hourthing = $lmvals[5];
				my @htvals = split(':', $hourthing);
				my $sec = $htvals[2];
				my $min = $htvals[1];
				my $hour = $htvals[0];
				my $wday = 0;
				my $yday = 0;
				my $lmseconds = timegm($sec, $min, $hour, $mday, $mon, $year, $wday, $yday);
				my $filetime = (stat $savefilename) [9]; # todo: make this be passed (fewer disk accesses)
				if ($filetime > $lmseconds) {
					dbgv("not lately modified, will use cached"); 
					$readfromcached = 1;
					$happywithcached = 30400;
				}
				else {
					dbgv("cached file older than latest modified, so will renew it");
				}
			}
		}
		# todo: i wonder if this should be more systematic--to catch all kinds of other errors besides 404
		if($line =~ /^HTTP.*304/) {
			dbgv("server responded with 304 - use cached $savefilename");
			if ($dontusecached) {
				dbgv("STRANGE... since dontusecached is true, weird to have if-modified-since...");
			}
			$readfromcached = 1;
			$happywithcached = 304;   # so we don't try parsing the header, etc.
		}
		if ($readfromcached) {
			my $filesize = -s $savefilename;
			if (!open(IN, $savefilename)) { 
				dbg("ERROR--can't read $savefilename (will attempt to continue): $!"); 
				last; 
			} 
			@$lines = <IN>;
			close IN;
			if (0) {
				# if set the file's last modified time so that -M * 24 * 60 goes back to 0 and don't check until
				#   again g_cachetime is expired, then it won't catch last-modified difference either... whoops...
				# todo CUE: is there a way to make so it works for cachetime expiration checks, but also works for
				#   last-modified?? hm...
				# that is, it should know that cached file was not really modified recently, but should know it
				# doesn't have to look again in the next $cachetime minute....
				my $now = time;
				utime $now, $now, ($savefilename);
				my $tmpmodtime = (-M $savefilename);
				dbgv("set modtime of $savefilename to now");
			}
			last;
		}	
		if($line =~ /^HTTP.*404/) {
			  dbg("*****404 on $requestmade *****");
			  printtoscreen("404 not found: $requestmade") if $toscreen;  # not sure what else to say.
			  cleanup(0, 0, 0, 0); # don't bother overwriting anything
			  $continueplease = 0;
			  $errorcode = 404;
			  last;
		}
		if ($line =~ /^Location: /i) { 
			  dbgv("here in Location line, original line is: $line");
			  $line =~ s/^Location: (.*)/$1/;
			  dbgv("got rid of the Location tag, now it's $line");
			  my ($redirdomain, $redirfile);
			  # only have 1 there (strict) if not subdomain
			  # if ($file =~ /^$g_subdomstr/) {
			  # below was a hack to make something happen, but that wasn't the problem--now it's unnecessary
			  # my $strictly = 1;
			  # if ($line =~ /^www\./) {
			 	# dbgv("because the thing starts with www., will not be strict in splitting ($line)");
			 	# $strictly = 0;
			  # }
			  ($redirdomain, $redirfile) = SplitURL($line, 1); # $strictly); # if strictly, requires http: sort of thing
			  dbgv("from that split got $redirdomain, $redirfile");
			  if (!$redirdomain) {
				if ($subdomain) {
					$redirdomain = $subdomain;
				}
				else {
					$redirdomain = $g_givemedomain;
				}
				dbgv("got no redirdomain (redirfile: $redirfile) from splitting; setting to $redirdomain");
				if (!($redirfile =~ /^\//)) {
					my $subdomainpath = "";
					if ($subdomain) { # could also just add the gotten subdomainpath onto basepath above--strips
						$subdomainpath = GetPathForSubdomain($subdomain); 
					}
					dbgv("here the subdomain is $subdomain, and the path from that is $subdomainpath");
					my $strip = $g_basepath;
					if ($g_cachedir) { $strip = "$strip/$g_cachedir"; }
					$strip = "$strip$subdomainpath";
					dbgv("before stripping, savefilename is $savefilename");
					my $savingdirname = GetFileDir($savefilename, $strip);
					dbgv("after stripping $strip, got savingdirname: $savingdirname");
					$redirfile = GetAppendedPath($savingdirname, $redirfile);
					dbgv("redirfile not start with /, so prepending fixed-up $savingdirname: $redirfile");
				}
			  }
			  my $origrdd = $redirdomain;
			  if ($g_mybaredomain) {
				  $redirdomain =~ s/$g_givemebaredomain/$g_mybaredomain/; # just to mask it a bit, visually
			  }

			  my $prepend;
			  if ($g_nomod) {
				$prepend = $g_basepath;
				if ($g_cachedir) { $prepend = "$prepend/$g_cachedir"; }
				
			  }
			  else {
				$prepend = $g_basedir;
			  }
			  my $newloc;
			  # note: to clean up, could use GetPathForSubdomain here
			  if ($origrdd ne $g_givemedomain) {  
				  $newloc = "$prepend$g_subdomstr/$redirdomain$redirfile"; 
			  }
			  else {
				  $newloc = "$prepend$redirfile"; 
			  }
			  dbgv("will redirect to $newloc");
			  if ($g_nomod) { 
				my $newlocfile = $newloc;
				my $params;
				my $endedwithq = 0;
				if ($newlocfile =~ s|(^\?)*\?(.*)|\1|) {
					$endedwithq = 1;
					$params = $2;
					$newloc = $newlocfile;
				}
				# my $params = $2; 
				# if ($params) { 
					# $newloc = $newlocfile;
				# }
				if ($toscreen) {
					my $newlocstub = MakeStub($newloc, $g_basepath);
					my $newlocredir = $newlocstub;
					if ($endedwithq) {
						$newlocredir = "$newlocredir?$params";
					}
					WriteRedirector($newlocredir, $savefilenamepending, $savefilename, 1); # 1 is: to screen
				}
				else {
					dbgv("asking dealwithfile to store in $savefilename (passed as $desiredsfn), not $newloc");
					my $errorcode = dealwithfile($newloc, $toscreen, 0, 0, "$params", $savefilename);
					$newloc = checkimageerror($newloc, $errorcode);
				}
			  }
			  else {
				WriteRedirector($newloc, $savefilenamepending, $savefilename); # for next time
				print "Location: $newloc\n\n" if $toscreen;
			  }
			  $continueplease = 0;
			  last;
		}
		if ($line =~ /^Content-Type/i) {
			  $startoutline = "$line\n";
		}
	}
	return ($continueplease, $startoutline, $happywithcached, $errorcode);
}

# this is called only from one of those start files--index.php, index.php3, index.cgi
sub indexcall {
	my ($phptype, $remoteip, $httphost, $requri) = @_;
	my $basepath = ".";

	init($remoteip, $basepath, $phptype);
	dbgv("indexcall inited");
	# dbgv("here in indexcall, got phptype: $phptype");

	my $reldir = $basepath;
	if ($g_cachedir) { $reldir = "$reldir/$g_cachedir"; }

	# the key is the / there??? or not...--check who calls indexcall
	my $newlocstub = MakeStub("$reldir/", $basepath);
	dbgv("indexcall made stub $newlocstub");

	my $ifn = "./index.html"; 
	dbgv("will writeredirector to file $ifn");

	# collect user information--just website location
	my $redirtoscreen = 1;
	my $regfile = "$reldir/reamweaverregistered.txt";
	if (!(-s $regfile)) {
		$redirtoscreen = 0;
		printtoscreen("<html><head>\n" .
			"<meta http-equiv='refresh' content='0; URL=" .
			"http://reamweaver.com/thankyou.php?host=$httphost&requri=$requri" .
			"'>\n" .
			"</head><body></body></html>\n");

		open(REG, ">>$regfile");
		print REG "registered $httphost at $requri\n";
		close(REG);
		chmod $g_permissions, $regfile;
	}
	WriteRedirector($newlocstub, "$ifn$g_pendingext", $ifn, $redirtoscreen);

	dbgv("indexcall finished");
}
sub init {
	my ($remoteaddr, $basepath, $stubtype) = @_;
	if (!$g_remoteaddr) {
		if ($remoteaddr) {
			$g_remoteaddr = $remoteaddr;
		}
		else {
			$g_remoteaddr = $REMOTE_ADDR;
		}
	}
	if ($basepath) {
		$g_basepath = $basepath;
	}
	if ($stubtype) {
		# dbgv("here in init, passed stubtype ($stubtype)");
		# this determines what sort of stub is used--in.cnn.cn.php3 for example, or none
		if (!($stubtype eq "php3") && !($stubtype eq "php") && !($stubtype eq "cgi") && !($stubtype =~ /rewrite/)) {
			dbgv("UNKNOWN STUBTYPE: $stubtype");
		}
		$g_stubtype = $stubtype;
		if ($g_stubtype =~ /rewrite/) { $g_nomod = 0; }
		else { $g_nomod = 1; }
	}
	# todo: below should not happen every request.... randomize or something....
	checkdbgfilesizeifnecessary();
	initializevariablesifnecessary();
}

sub initializevariablesifnecessary {
	if (!$g_variablesinited) {
		if (!$g_basepath) { 
			if ($g_nomod) {
				$g_basepath = ".";  # was ".."
			}
			else {
				$g_basepath = "..";
			}
		}
		else {
			$g_basepath =~ s|/$||;
		} 
		if ($g_weblocation) {
			($g_mydomain, $g_basedir) = SplitURL($g_weblocation, 0); # 0 -> not strict--no need to include protocol
		}
		if ($g_cgiurl) {
			$origcgiurl = $g_cgiurl;
			if (!($g_cgiurl =~ /\/$/)) {
				$g_cgiurl = "$g_cgiurl/";
			}
			if ($origcgiurl =~ /^\//) {
				$g_cgiurl =~ s|^/||;
			}
		}
		else {
			$g_cgiurl = "";
		}
		if (!$g_givemedomain) {
			my $errmess = "ERROR: you must have a \$givemedomain in reamweaver.conf";
			dbg($errmess);
			printtoscreen($errmess);
			exit(0);
		}
		$g_givemedomain =~ s|([^:]+)://||; # lose the beginning http:// type crap
		$g_givemedomain =~ s|/$||; # lose any slash at the end
		if ($g_givemedomain =~ /\//) {
			my $errmess = "ERROR: \$givemedomain in reamweaver.conf cannot have subdirectories ".
						"(you have $g_givemedomain)";
			dbg($errmess);
			printtoscreen($errmess);
			exit(0);
		}
		$g_mybaredomain = $g_mydomain;
		if ($g_mybaredomain) {
			$g_mybaredomain =~ s/^www\.//i; # added \ before . 20020510
		}
		$g_givemebaredomain = $g_givemedomain;
		$g_givemebaredomain =~ s/^www\.//i; # added \ before . 20020510
		if (!($g_givemealsogreedy =~ /\b$g_givemebaredomain\b/)) {
			if ($g_givemealsogreedy) {
				$g_givemealsogreedy = "$g_givemebaredomain, $g_givemealsogreedy";
			}
			else {
				$g_givemealsogreedy = $g_givemebaredomain;
			}
			# dbgv("since givemealso didn't have $g_givemebaredomain, added it: $g_givemealsogreedy");
		}
		if (!$g_referer) {
			$g_referer = $g_givemedomain;
			# dbgv("set referer to $g_referer");
		}
		else {
			$g_referer =~ s|([^:]+)://||; # lose the beginning http:// type crap
		}
		if (!$g_threeletters) {
			if ($g_givemebaredomain) {
				$g_threeletters = $g_givemebaredomain;
				$g_threeletters =~ s/([^\.][^\.][^\.]).*/\1/;
			}
			if (!$g_threeletters) { $g_threeletters = "hdd"; }
		}
		if (!$g_twoletters) {
			if ($g_givemebaredomain) {
				$g_twoletters = $g_givemebaredomain;
				$g_twoletters =~ s/([^\.][^\.]).*/\1/;
			}
			if (!$g_twoletters) { $g_twoletters = "to"; }
		}
		if (!$g_allletters) {
			if ($g_givemebaredomain) {
				$g_allletters = $g_givemebaredomain;
				$g_allletters =~ s/\.[^\.]*$//; # trim off end
			}
			if (!$g_allletters) { dbgv("ERROR--no allletters somehow with givemebaredomain $g_givemebaredomain"); }
		}
		if ($g_slashplaceholder) {
			$g_slashplaceholder = "$g_slashplaceholder.";
		}
		$g_slashplaceholder = "$g_slashplaceholder$g_threeletters";
		if ($g_nomod) {
			$g_placeaddext = $g_stubtype;
			$g_placeaddext = ".$g_twoletters.$g_placeaddext";
			# dbgv("the extension will be $g_placeaddext");
		}
		$g_variablesinited = 1;
	}
}
sub WriteRedirector {
	my ($newloc, $savefilenamepending, $savefilename, $toscreen) = @_;
	if ($savefilename) {
		  my $fh = FileHandle->new();
		  open($fh, ">$savefilenamepending") || dbg( "ERROR: No create relocation $savefilename. $!" ); 
		  chmod $g_permissions, $savefilenamepending; # what's this for????
		  flock($fh,2);
		  my $output = 	"<html>\n<head>\n" .
		  		"<meta http-equiv='refresh' content='0; URL=$newloc'>\n" .
		  		"</head>\n<body>\n\n\n\n</body></html>";
		  print $fh $output;
		  cleanup(1, $savefilenamepending, $savefilename, $fh); # overwrite it
		  if ($toscreen) {
			dbgv("printing redirector to screen as well as writing");
			printtoscreen($output);
		  }
	}
	else {
		  dbg("ERROR!!! no savefilename");
	}
}

sub GetPathForSubdomain {
	my ($subdomain) = @_;
	my $ret = ""; 
	
	# if ($subdomain && ($subdomain ne $g_givemedomain)) {
	#
	# todo: below, need somehow to check also for subdomains like www.time.com?
	#
	if ($subdomain && !($subdomain =~ /^$g_givemedomain$/i)) {
		my $subdomainalt = $subdomain;
		if ($g_mybaredomain) {
			$subdomainalt =~ s/$g_givemebaredomain/$g_mybaredomain/; # visually mask
		}
		$ret = "$g_subdomstr/$subdomainalt";
	}
	return $ret;
}
sub GetFileDir {
	my ($filename, $stripfromfront) = @_;
	$filename =~ s|[^/]*$||; # trim off all at end that isn't a slash
	if ($stripfromfront) {
		$filename =~ s/^$stripfromfront//;
	}
	if (!$filename) { $filename = "/"; }
	return $filename;
}

sub rearslashonly {
	my ($rep) = @_;
	$rep =~ s|^/||; 
	$rep =~ s|^\./||;
	if ($rep ne "") { $rep = "$rep/"; }
	return $rep;
}

sub MakeStub { # takes a RELATIVE path from the base...
	my ($fn, $basepath) = @_;
	dbgvv("entering MakeStub wih $fn");
	$g_dbgtabs = $g_dbgtabs + 1;

	my $placeadd = $g_placeaddext;
	my $fndirectory = "";
	my $isindex = 0;

	# dow: removed bottom three lines
	# $fn =~ s|/index\.htm[l]?$|/|;
	# $fn =~ s|/default\.htm[l]?$|/|;
	# $fn =~ s|/welcome\.htm[l]?$|/|;
	# NOTE: ALTERNATIVE TO THIS would be to save the cache files in something slightly
	# different from the actual filename.... that way wouldn't try to write over directories...
	# might be good to do because of this + situation anyhow, sort of thing...
	

	# if there's a /../ in the middle of the name, fix that... will be weird otherwise...
	$fn = RegularizePath($fn);
	# note--might be good to do this everywhere...

	my $stripfromstart = $basepath;
	if ($g_cachedir) {
		$stripfromstart = "$stripfromstart/$g_cachedir";
	}
	my $newsavingdirname = 0;
	# todo: might be other things to check--cnn.com type thing (with no trailing slash) is checked for in
	# 	GrabRefs, but there might be other such references...
	if ($fn =~ /\/[^\.\/]+$/) { # seems to be a directory but without a trailing slash...
		if (0 && $fn =~ /[^\/]+\+[^\/]+$/) { # at end, in last bit
			dbgv("hacking--got +, so missing the thing in $fn"); # i think this is for lefigaro.fr only...
			# this would also fix the link situation in weforum, but is just too much of a hack....
		}
		else {
			# todo: okay, maybe this should be done also for other parts in code??? or not...
			$newsavingdirname = GetFileDir($fn, $stripfromstart);
			# dbgv("because $fn looks like it might be a file at next-up directory level, will " .
			#	"pass new savingdirname for references with the stubs to be written: $newsavingdirname");
			$fn = "$fn/";
		}
	}

	my $fileforscript = $fn;
	$fileforscript =~ s|^$stripfromstart||;

	# dow
	$fndirectory = $fn;
	$fndirectory =~ s|/([^/]*)$|/|;
	my $filealone = $1;
	# dbgv("fndirectory is: $fndirectory; filealone = $filealone");
	# perhaps it needs to take an argument, the filename to use here? for index.html
	if ($fn =~ /\/$/) { # if ends with slash 
		$isindex = 1;
		if ($filealone) {
			dbgv("oops!! $fn got filealone $filealone even though ends with slash");
		}
		if ($fn ne $fndirectory) {
			dbgv("oops!! $fn not $fndirectory!!!!");
			exit(0);
		}
		$filealone = $g_slashplaceholder;
		# $filealone = "$g_slashplaceholder$placeadd";
		# $fndirectory = $fn;
		# $fn = "$fndirectory$filealone";
		# $fndirectory = "$basepath$fndirectory"; 
	}
	elsif ($fn =~ /index\.htm[l]?$/ || $fn =~ /welcome\.htm[l]?$/ || $fn =~ /default\.htm[l]?$/) {
		# $placeadd = "index.html$placeadd"; # total hack
		$isindex = 1;
	}
	$filealone = "$filealone$placeadd";
	$fn = "$fndirectory$filealone";
	# $fn = "$fn$placeadd"; # now should be what was subbed above into the line (unless /)
	dbgv("now fn is $fn");

	my $fnfrombase = $fn;
	$fnfrombase =~ s|^$basepath||;
	# todo: instead of using the passed basepath, just remove any ../ from before, then
	#	add /  --- so don't depend on passed basepath
	my $testfnfrombase = $fn;
	$testfnfrombase =~ s|^(\.\.?/)*||;
	if ($testfnfrombase !~ /^\//) {
		$testfnfrombase = "/$testfnfrombase";
	}
	if ($fnfrombase ne $testfnfrombase) { dbgv("HOOHOO--didn't get same resulting $fnfrombase, $testfnfrombase"); }

	unless (-e $fn) {
		dbgv("will make $fn");
		makedirectories($fn);
		my $phn = $fn;
		my $phnpending = "$phn$g_pendingext";
		my $ph = FileHandle->new();
		open($ph, ">$phnpending") || dbg("ERROR: not create placeholder $phnpending. $!");
		flock($ph, 2);
		my $newrelbasepath = GetBasePath($fnfrombase);

		

		my $scriptpath = $newrelbasepath;
		if ($scriptpath) {
			$scriptpath = "$scriptpath/";
		}
		$scriptpath = "$scriptpath$g_cgiurl";
		# dbgv("new scriptpath to pass here in $fn");
		# my $scriptpath = "$newrelbasepath$g_cgiurl";
		if (!$newrelbasepath || ($newrelbasepath eq "")) {
			$newrelbasepath = ".";
		}
		# Next, write php or perl as necessary.
		if ($g_stubtype eq "cgi") {
			print $ph "#!$g_perlpath\n"; 
			print $ph "require '$scriptpath" . "reamweaver.conf';\n";
			print $ph "require '$scriptpath" . "reamweaverlib.pl';\n\n";
			# TEST: here, put $newsavingdirname in place of the appropriate 0
			my $dcmd = "dealwithfile(\"$fileforscript\", 1, \"$newrelbasepath\", 0, " .
					"\\\@ARGV, 0, \"$g_stubtype\"";
			if ($newsavingdirname) {
				$dcmd .= ", 0, \"$newsavingdirname\"";
			}
			$dcmd .= ");\n";
			print $ph "$dcmd";
		}
		else {
			print $ph "<?\n\n";
			print $ph "\$parms = 0;\n";
			print $ph "if (ereg(\"\\?\", \$REQUEST_URI)) {\n";
			print $ph "   \$parms = \$REQUEST_URI;\n";
			print $ph "   \$parms = ereg_replace(\"[^\\?]*\\?\", \"\", \$parms);\n";
			# print $ph "   \$parms = ereg_replace(\"\\&\", \"\\\\&\", \$parms);\n";
			print $ph "}\n\n";
			
			my $command = "$g_perlpath $scriptpath" . "reamweaverphp.pl " .
						"$fileforscript $newrelbasepath " .
						# "$scriptpath $g_stubtype \\\"\$parms\\\" \$REMOTE_ADDR";
						"$g_stubtype \\\"\$parms\\\" \$REMOTE_ADDR $newsavingdirname";

			print $ph "\$command = \"$command\";\n";
			print $ph "passthru(\$command);\n";
			print $ph "\n\n";
			print $ph "?>\n";
		}
		cleanup(1, $phnpending, $phn, $ph);
		chmod $g_permissions, $phn; # executable
	}
	if ($isindex) {
		my $indexfilename = "$fndirectory" . "index.html";
		my $makeit = 0;
		if (!(-e $indexfilename)) {
			$makeit = 1;
		}
		else {
			# open $indexfilename and see if it contains URL=$placeadd
			open(READI, "$indexfilename");
			my @indexlines = <READI>;
			my $indexfull = join("\n", @indexlines);
			# if (!($indexfull =~ /$placeadd/)) {
			if (!($indexfull =~ /$filealone/)) {
				$makeit = 1;
			}
			close(READI);
		}
		if ($makeit) {
			my $indexfilenamepending = "$indexfilename$g_pendingext";
			my $ih = FileHandle->new();
			open($ih, ">$indexfilenamepending") || dbg( "ERROR: no create $indexfilenamepending. $!" ); 
			flock($ih, 2);
			my $title = $g_givemedomain;
			my $putinframes = 0;
			print $ih "<html>\n";
			print $ih "<head>\n";
			print $ih "<title>$title</title>\n";
			if ($putinframes) {
				print $ih "</head>\n";
				print $ih "<FRAMESET rows='100%,*' NORESIZE frameborder='no'\n";
				print $ih " framespacing='0' scrolling='0' border='no'>\n";
				print $ih "<frame src='$filealone' name='main' \n";
				print $ih " marginheight=0 marginwidth=0 frameborder=0 border=0 scrolling=auto>\n";
				print $ih "</FRAMESET>\n";
				print $ih "<noframes>\n";
				print $ih "<head>\n";
				print $ih "<title>$title</title>\n";
			}
			print $ih "<meta http-equiv='refresh' content='0; URL=$filealone'>\n";
			print $ih "</head>\n";
			if ($putinframes) {
				print $ih "</noframes>\n";
			}
			print $ih "</html>\n";
			cleanup(1, $indexfilenamepending, $indexfilename, $ih);
		}
	}
	$g_dbgtabs = $g_dbgtabs - 1;
	dbgvv("returning from MakeStub with $fn");
	return $fn;
}
sub GetSubListNames {
	my ($basepath) = @_;
	if (!$g_sublistsfigured) {
		if (!$g_fluffmode) {
			if ($g_sublist) {
				my @sublists = split(",", $g_sublist);
				my $sublist;
				foreach $sublist(@sublists) {
					$sublist =~ s/^\s//; # trim start space
					$sublist =~ s/\s$//; # trim end space
					$sublist = "$basepath/$sublist";
					if (-s $sublist) {
						dbgv("specified $sublist found; will use");
						push(@g_sublists, $sublist);
					}
					else {
						dbg("WARNING: specified $sublist, but it doesn't exist");
					}
				}
			}
			else {
				my $sublistbase = "$basepath/substitutions";
				if ($g_allletters) {
					my $try1 = "$sublistbase-$g_allletters.txt";
					if (-s $try1) {
						push(@g_sublists, $try1);
					}
				}
				my $try2 = "$sublistbase.txt";
				if (-s $try2) {
					push(@g_sublists, $try2);
				}
				my $numlists = @g_sublists;
				dbgv("$numlists lists found");
			}
		}
		else {
			dbgv("ERROR: blank flufflist although in fluffmode") if !$g_flufflist;
			my $fluffplace = "$basepath/$g_flufflist";
			push(@g_sublists, $fluffplace);
		}
		$g_sublistsfigured = 1;
	}
	return @g_sublists;
}
sub fixsublisttime {
	my ($sublist, $sublisttime) = @_;
	if (!$sublisttime) {
		$sublisttime = (stat $sublist) [9];
	}
	my $now = time;
	if ($sublisttime > $now) {
		dbgv("because $sublisttime > $now, seems in future--syncing");
		# chmod 0755, $sublist; # doesn't do any good... has to be done by the uploader
		utime $now, $now, ($sublist);
		my $newsublisttime = (stat $sublist) [9];
		dbgv("now sublisttime is $newsublisttime");
		system("touch $sublist");
		$newsublisttime = (stat $sublist) [9];
		dbgv("and after touch, is $newsublisttime");
	}
}

sub RegularizePath {
	my ($fn) = @_;
	my $testing = 0;
	if ($testing || ($fn =~ /[^\.]\/\.\./)) {
		# dbgv("got into RegularizePath loop; pathname before: $fn");
		my $longandtiresomeway = 1; # it is MUCH, much faster
		if ($longandtiresomeway) {
			my $perfectpath = "";
			if ($fn =~ /^\//) {
				$perfectpath = "/";
			}
			my @pathparts = split(/\//, $fn);
			my $paststart = 0; # have we gotten past the .. and . stuff?
			my $pathbit;
			while (defined($pathbit = shift(@pathparts))) {
				# if $pathbit is .., you have to remove a ../ from the $newrelbasepath, and don't add one on...
				my $writebit = 1;
				if ($pathbit eq "..") {
					if ($paststart) {
						$writebit = 0;
						if (!($perfectpath =~ s|[^/]*/$||)) {
							dbg("whoopsydaisy, couldn't remove trailing thing from the damn $perfectpath");
						}
					}
				}
				# if $pathbit is ., then just ignore the damn thing
				elsif ($pathbit eq ".") {
					if ($paststart) {
						dbgv("found a $pathbit paststart in $fn  -- won't write");
						$writebit = 0;
					}
				}
				else {
					$paststart = 1;
				}
				if ($writebit) {
					$perfectpath .= "$pathbit/";
				}
			}
			if ($fn =~ /\/$/) {
				if ($perfectpath !~ /\/$/) {
					$perfectpath .= "/";
				}
			}
			else {
				if ($perfectpath =~ /\/$/) {
					$perfectpath =~ s|/$||;
				}
			}
			$fn = $perfectpath;
		}
		else {
			# $fn =~ s|/([^/\.]*\.?[^/\.]+)+/\.\./|/|g;
			$fn =~ s|/([^/\.]*\.?[^/\.]+)+/\.\./|/|; # these take FOREVER...
		}
		# dbgv("      and after: $fn");
	}
	return $fn;
}

sub GetBasePath {
	my ($fnfrombase) = @_;
	my @pathparts = split(/\//, $fnfrombase);
	my $newrelbasepath = "";
	my $pathbit;
	my $skipped_one = 0;
	while (defined($pathbit = shift(@pathparts))) {
		# if $pathbit is .., you have to remove a ../ from the $newrelbasepath, and don't add one on...
		# Below shouldn't be necessary any longer, now that RegularizePath is used...
		if ($pathbit eq "..") {
			dbgv("HMMMMMMM.... this ..-trimming bit shouldn't ever get called anymore.......");
			if (!($newrelbasepath =~ s|\.\./$||)) {
				dbg("whoopsydaisy, couldn't remove trailing ../ from the damn $newrelbasepath");
			}
			else {
				dbgv("having found a .., cut ../ from $newrelbasepath");
			}
		}
		# if $pathbit is ., then just ignore the damn thing
		elsif ($pathbit eq ".") {
			dbgv("HMM WOW HMM.... that's weird... how got a . for pathbit???? $fnfrombase");
		}
		else {
			# not sure actually how this $skipped_one bit fits into this nonsense... one vodka too many...
			if ($skipped_one > 1) { $newrelbasepath .= "../"; }
			$skipped_one++;
		}
	}
	$newrelbasepath =~ s|/$||; # doesn't need the last / if any
	return $newrelbasepath;
}
sub GetAppendedPath {
	my ($sdn, $fn) = @_;
	dbgv("in GetAppendedPath, starting with $fn");
	$fn =~ s|^\./||; 
	dbgv("   after removing initial . : $fn");
	while ($fn =~ /^\.\.\//) {
		$fn =~ s/^\.\.\///; # trim off initial ../
		dbgv("   after removing initial .. : $fn");

		# trim off the final blahblah/
		# but:	sometimes html can use too many ../../ without problem if the idea is to get to root level.
		# 	we have to account for that. So:
		# 		exception 1: if $sdn is /, don't trim (can't anyhow)
		# 		exception 2: if $sdn is /$g_subdomstr/anything/, don't trim--you're at the root there

		if ($sdn =~ /$g_subdomstr\/[^\/]*\/$/) {
			dbgv("(subdomstr) html seems to be asking too low: $fn is asked for a level down, ".
					"but $sdn has nothing left to trim; will ignore"); 
		}
		elsif (!($sdn =~ /[^\/]*\/$/)) { 
			dbgv("html seems to be asking too low: $fn is asked for a level down, ".
					"but $sdn has nothing left to trim; will ignore"); 
		}
		else {
			$sdn =~ s|[^/]*/$||; # trim off final blahblah/ (directory)
			dbgv("   sdn, meanwhile, is $sdn");
		}


	}
	dbgv("in GetAppendedPath, finishing with $fn");
	$fn = "$sdn$fn";
	dbgv("   and after adding $sdn: $fn");
	return $fn;
}


# prepends 0s to a number
sub FormatSuff {
	my ($suf) = @_;
	if ($suf < 10) {
		$suf = "00$suf";
	}
	elsif ($suf < 100) {
		$suf = "0$suf";
	}
	elsif ($suf < 1000) {
		$suf = "$suf";
	}
	else {
		dbg("ERROR: more than 1000 items in line??? $line");
	}
	return $suf;	
}


# Gets all files in $line that are signalled either by $pref (href=, src=, etc.) or by $ext (.gif, etc.).
# Puts the gotten files into the array and returns that array along with current increment for it.
sub GrabRefs {
	my ($line, $pref, $pre, $ext, $makestubs, $filerefsarrayname, $markcnt, 
				$stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath) = @_;
	dbgvv("entering GrabRefs with $pre, $ext");
        my @filerefs = @$filerefsarrayname;
	my $startdelims = $g_startdelims;

	# my $tmpverbatim = 0;
 	# if ($line=~/verbatim/) {
		# $tmpverbatim = 1;
		# dbgv("got verbatim: $line");
	# }

	# TODO: probably should grab whole thing, including the params, and separate it out once you have
	#	the filename--this will enable fixing secondary ?s to something else so that no server error
	#	with double (see time box on cnn.com)
	my $enddelims = "\?#>$startdelims"; # we don't want to delimit at start by ? or #, because that would give
		# us parameters and anchors, which are quite special
	$enddelims =~ s/=//; # a = can be in the filename, so don't avoid it at end

	my $namecharsnot = "é$enddelims"; # what the filename should not contain
	my $firstcharnot = "$namecharsnot"; 
	$firstcharnot = "+$firstcharnot"; # to fix problem in dupont.com--at the same time causes other... oops...

	my $nofilenamestring = "oiuashoieyurta987zkdsjfgoiuappp"; # better i guess to test for defined($filename), right?
	while (1) {
		my $marksuf = FormatSuff($markcnt);
		my $mark = "$stdmark$marksuf"; # unique mark to substitute for filename until finished processing line
			# allows subsequent subs not to count this again
		my $filename = $nofilenamestring;
		my $interestedinfile = 1;
		# get the full path name (everything before and including the $ext and after starting $startdelims)
		#   note: the [^+][$startdelims] is to avoid one case in CNN of ... +"icon.gif", that shouldn't be changed
		if ($ext) {
			# Wish to force SOMETHING to come between beginning of line and filename start.... but that's too hard...
			# do it checks instead
			if ($line =~ s|^(.*[^+]\s*[$startdelims])?([^$namecharsnot]+$ext)([$enddelims].*)?$|$1$mark$3|i) {
				$filename = $2;
				# used to have the ^$mark check here...
			}
		}
		# get the full path name (everything after $pref and $startdelims, and before final $enddelims);
		elsif ($pref) {
			if  ($line =~ 
				s|($pref)([$startdelims]?)([^$firstcharnot][^$namecharsnot]*)([$enddelims].*)|$1$2$mark$4|i)
			{
				$filename = $3;
				if ($pre) {
					if ($filename !~ /^$pre/) {
						# dbgv("$filename gotten with $pref, but not start with $pre, so not interested!");
						$interestedinfile = 0;
					}
					else {
						# dbgv("$filename, gotten with $pref, does start with $pre, so we're interested!");
					}
				}
			}
		}
		# get the full path name (everything after and including the $pre and until starting $startdelims)
		elsif ($pre) {
			if ($line =~ s|^(.*[$startdelims])?($pre[^$namecharsnot]+)([$enddelims].*)?$|$1$mark$3|i) {
				$filename = $2;
			}
		}

		if ($filename ne $nofilenamestring) {

			#### checks for stupid javascript stuff that could have gone wrong... ####
			my $nsy = 1;
			if ($line =~ /^$mark/) { # this.html = something, for example
				dbgv("REJECTION: got $filename, but at beginning of line and so we don't want it: $line") if $nsy;
				$interestedinfile = 0;
			}
			elsif ($line =~ /$mark\s*=/) { # same thing... just in case....
				dbgv("REJECTION: got $filename, but followed by an =, so we don't want it: $line") if $nsy;
				$interestedinfile = 0;
			}
			# elsif ($filename =~ /\]/) {
			# 	dbgv("REJECTION: $filename seems to be an array reference") if $nsy;
			# 	$interestedinfile = 0;
			# }
			# elsif ($filename =~ /\.nsf$/) { # note: should probably test for not in mimetypes instead... elsewhere...
			# 	dbgv("REJECTION: $filename ends with nsf, which is odd--homepublic.nsf problem in weforum") if $nsy;
			# 	$interestedinfile = 0;
			# }
			elsif ($filename =~ /[\[\]\;\{\}]/) {
				dbgv("REJECTION: $filename seems to be from javascript") if $nsy;
				$interestedinfile = 0;
			}
			elsif ($filename =~ /^this\./) {
				dbgv("REJECTION: $filename starting with 'this.'--most likely javascript") if $nsy;
				$interestedinfile = 0;
			}
			elsif ($line =~ /$mark\(/) {
				dbgv("REJECTION: $filename immediately followed by ( in line--probably javascript: $line") if $nsy;
				$interestedinfile = 0;
			}
			#### end checks for stupid javascript stuff


			my $processfile = 0;
			my $gotmatchedurl = 0;
			my $fnref = 0; # what the ref to the file should be (based on the original url gotten)--
			my $fn = $filename;
			my $fnorig = $filename;
			my $prepend = $basepath;
				   # this will be put in place of the mark above, after the whole line has been processed.
			if ($interestedinfile) {
				if ($g_nomod) {
					if ($g_cachedir) { $prepend = "$prepend/$g_cachedir"; }
				}

				# check for the matching of urls in the $fn
				my $matchurl, $repurl;
				my $matchind = 0;
				while ($matchurl = @g_matchurls[$matchind]) {
					$matchind++;
					$repurl = @g_matchurls[$matchind];
					$matchind++;
					# dbgv("got here match thing $matchurl, $repurl");
					if ($fn =~ /$matchurl/) {
						dbgv("found that $fn matched $matchurl ; will set it to $repurl");
						$fn = $repurl;
						$gotmatchedurl = 1;
						last;
					}
				}
				if (!$gotmatchedurl) {
					# interpret the filename
					if ($fn =~ s|^([^:]+:)||) { # if you got some sort of "http://" thing at the beginning
						my $protocol = $1;
						if ($protocol !~ /javascript/ && $protocol !~ /mailto/) { # todo: other possibilities 
										 # 	 for 'href="javascript:' type things
							if (!($fn =~ s|^//||)) {
								dbg("WARNING--with $protocol remd from start, '$fn' no start w //");
							}
							my $checkdom;
							foreach $checkdom(@g_checkdoms) { 
								my $domainisspecific = 0;
								if ($checkdom =~ /^s:/) {
									$domainisspecific = 1; # todo: use this or not
									$checkdom =~ s/^s://;
								}
								$checkdom =~ s/^\s*(.*)\s*$/\1/; # no spaces
								if ($fn =~ /$checkdom/) { # slight optimization
									my $replacedom = $checkdom;
									# for using: (fyi.cnn.com => fyi.theyesmen.org)
									my $subdom = $g_givemebaredomain;
									if ($g_mybaredomain) {
										$subdom = $g_mybaredomain;
										$replacedom =~ s/$g_givemebaredomain/$subdom/; 
									}
									# fyi.cnn.com/file.html => fyi.theyesmen.org/file.html
									# TEST: changed the * after paren from ? --
									#	also... would it be better to 
									# 	use [:alpha] or something
									# 	that means letters and numbers???
									if ($fn =~ s|^(([^\./]*\.)*)$checkdom|$1$replacedom|i) { 
										$processfile = 1; # else it's just some http address
										# below should get rid of port shit on the domain
										my $dbgfnorig = $fn;
										if ($fn =~ s|^([^/:]+):[0-9]+/|$1/|) {
											dbgv("remd port from $dbgfnorig; now $fn");
										}
										# => /affiliates/fyi.theyesmen.org/file.html
										# if there's no / in the $fn (e.g. cnn.com), 
										# 	add one onto the end
										if ($fn =~ /^[^\/]*$/) {
											dbgv("found raw domain: $fn");
											$fn .= "/";
										}
										$fn = "$g_subdomstr/$fn"; 

										# /affiliates/www.theyesmen.org/file.html => 
										# /file.html
										if (!($fn =~ s|(^$g_subdomstr/$subdom)||)) { 
											# /affiliates/theyesmen.org/file.html => 
											# /file.html
											if ($g_mydomain) {
											$fn =~ s|(^$g_subdomstr/$g_mydomain)||; 
											}
											else {
											$fn =~ s|(^$g_subdomstr/$g_givemedomain)||; 
											}
										}
										$fn = "$prepend$fn"; # now passable to dealwithfile
									}
								}
							}
						}
					}
					else {
						$processfile = 1;
						if ($fn =~ /^\//) { # is referred to in an absolute path--make relative
							$fn = "$prepend$subdomainpath$fn";
						}
						else { # rel path--assume starts from $savingdirname, then make relative anyhow
							# $fnref = $fnorig; # you don't want to change the thing in the html
									# problematic--what about the extension...
							$fn = GetAppendedPath($savingdirname, $fn);
							# note: $savingdirname may already have that cachedir in there, no???
							$fn = "$prepend$fn";
						}
					}
				}
			}

			if ($gotmatchedurl) {
				$fnref = $fn;
				dbgv("since got matched url, fnref is now $fnref");
			}
			elsif (!$processfile) { # if it was an uninteresting http reference, basically
				$fnref = $filename;
			}
			else {
				if ($g_nomod) {
					$fn =~ s|\&amp\;|\&|g; # weirdness
					if (!$makestubs) {
						# download the file, basically--parsing if necessary
						$errorcode = dealwithfile($fn, 0, $basepath, $markbasepath, 
											0, 0, 0, 0, $savingdirname);
						$fn = checkimageerror($fn, $errorcode);
					}
					else {
						# make the stub, which takes care of getting/parsing the thing when it is called.
						# it comes out looking like /path/to/file.html.eu.php3, for example
						# (could do this for each thing in the page, but more efficient this way)
						$fn = MakeStub($fn, $basepath);
					}
					$fnref = $fn;

					# %5C (for example) in a made path must now be replaced with %255C in the 
					#    reference that's used in the html-- % is encoded as %25
					$fnref =~ s/\%/\%25/g;
				}
			}
			# store in simple array so can fix up line afterwards--will know to get by order in array
			push(@filerefs, $fnref); # $fnref is either the unchanged file ref, or the changed one
			$markcnt ++;
		}
		else {
			last;
		}
	}
	dbgvv("returning from GrabRefs");
	return ($line, $markcnt, \@filerefs);
}

# Gets all files referred to in a line, as figured from extensions and tags.
# The order that extensions and tags are considered is important (see comments).
# For each file, either downloads it or makes a stub for it.
# Also performs all user specified substitutions if $dousersubs is 1.
sub DoMostSubs { # previously GrabAllRefs
	my ($line, $savingdirname, $subdomainpath, $basepath, $markbasepath, $dousersubs, $mimetype) = @_;
	dbgvv("entering DoMostSubs");		
	local @filerefs = ( ); # local makes it readable by sub-functions... this *may* be necessary
	my $markcnt = 0;
	my $stdmark = "éoaiusdflk"; # starts with é so that can avoid matching on it....

	#########################################################
	# do stylesheets first, before href--they're referred to with href, but are not to be stubbed
	($line, $markcnt, $frs) = GrabRefs($line, 
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.css', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	# todo: replace |(base href=")$basedir|$1http://$g_weblocation|   -- for msn.com
	# $line =~ s|(base\s*href\s*=\s*[$g_startdelims]?)

	# check all remaining hrefs, making stubs (large images will thus be stubbed rather than downloaded now)
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\shref\s*=\s*',# preface (use the initial \s to not match on javascript)
						0,		# prefix of file (e.g. http://)
						0, 		# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	#########################################################

	#########################################################
	# now do remaining images, html, etc. (that weren't caught above)
	# note--may have to parse .ram
	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.ram', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.gif', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.jpg', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.html', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.htm', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.php', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.php3', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.asp', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.jsp', 	# extension of file
						1, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.js', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						0,  		# preface--tagstart
						0,		# prefix of file (e.g. http://)
						'\.swf', 	# extension of file
						0, 		# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	#########################################################

	# TODO: put this somewhere better--has to be before the window.open has been subbed out (somewhere below)
	#	for onClick="javascript:window.open('/time/verbatim/20020909/',
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'window\.open\(',	# preface--tagstart
						'\/',			# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'LaunchVideo\(',	# preface--tagstart
						'\/',			# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;


	#########################################################
	# below ones are for frame, iframe, and layer src tags--it can happen that ref is directory...
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\<iframe\s[^\>]*\ssrc\s*=\s*',  	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\<frame\s[^\>]*\ssrc\s*=\s*',  	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\<layer\s[^\>]*\ssrc\s*=\s*',  	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	#########################################################

	#########################################################
	# clean up by calling with pref = src, and whatever other tags may have been missed
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\ssrc\s*=\s*',  	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						0, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\saction\s*=\s*',	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	# refresh tag
	($line, $markcnt, $frs) = GrabRefs($line,
						'\scontent\s*=\s*["\'][0-9]*;\s*url\s*=\s*',	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	#########################################################

	# do this, but not for cnn.com... hack... complicated javascript thing with i.cnn.net images on "print this" things
	if ($g_givemedomain !~ /cnn.com/) {
		($line, $markcnt, $frs) = GrabRefs($line, 	
						0,	# preface--tagstart
						# '[^G]..http://',		# prefix of file (e.g. http://)
							# the ^G stuff is an awful hack--just eliminate it until better solution
						'http://',		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
		@filerefs = @$frs;
	}


	##########################################################
	# if you find, in a list or after a = , something beginning with /, assume it's a file--for safety, always make stub
	($line, $markcnt, $frs) = GrabRefs($line,
						'\,\s["\']',	# preface--this one works
						# '\,\s["\']?',	# note: doesn't work
						# '\,\s',	# note: doesn't work either
						'\/',		# prefix of file (e.g. http://, /)
							# MYSTERY: explanation: it's just searching for anything
							# prefaced by one of those strings, and beginning with the next
							# parameter--so
							# 
							# [CASE A]
							# prefaced by: ,\s
							# and beginning with: /
							# 
							# see? so:        "a", "/b", c, /d
							# 
							# should get as files b and d (the full regex code in GrabRefs allows an
							# optional ' or ").
							# 
							# the mystery is that using
							# 
							# [CASE B]
							# prefaced by: \s*=\s*
							# and beginning with: /
							# 
							# works fine--the GrabRefs code does correctly allow the optional ' or "
							# (the way it does that is with [$g_startdelims] or something). But with
							# CASE A, it doesn't--you have to explicitly specify the optional ' or "  
							# (["']).
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;

	# todo: fix this... fails for homepublic.nsf
	($line, $markcnt, $frs) = GrabRefs($line,
						'\s*=\s*',	# preface--tagstart # MYSTERY: why does the " 
								# have to be included here, and not for href etc. above?
						'\/',		# prefix of file (e.g. http://, /)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	##########################################################

	my $tmpmrk = "éaoiubjlsdkfjoaisduf";
	$line =~ s/function popup/$tmpmrk/i; # don't want to get that when subbing on popup
	($line, $markcnt, $frs) = GrabRefs($line, 	
						'\spopup\(',	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						1, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
	@filerefs = @$frs;
	$line =~ s/$tmpmrk/function popup/;


	# here are some hacks for specific cases
	if ($g_givemedomain =~ /philipmorris/) { # note--this still doesn't work--need to get the image.... imghack
		# this one is just for a line in philipmorris.com: 
		# var imgUrl = '/images/pm_nf_' + objectID + './_off_img.jpg'
		# NOTE: the above is now caught in the = / GrabRefs, so this one is not needed any longer.
		($line, $markcnt, $frs) = GrabRefs($line, 	
							'imgurl\s*=\s*',	# preface--tagstart
						0,		# prefix of file (e.g. http://)
						0, 			# extension of file
						0, 			# make stubs?
					\@filerefs, $markcnt, $stdmark, $savingdirname, $subdomainpath, $basepath, $markbasepath);
		@filerefs = @$frs;
	}
	# probably do on 'OpenWindow(' and whatever else


	# now, while the URLs are properly masked, do the user specified substitutions
	if ($dousersubs) {
		dbgvv("about to dousersubs stuff");
		ParseSublines(); # only does it if necessary
		my $strict = 0;
		if ($mimetype eq 'text/html') { 
			$strict = 1; 
		}
		else {
			dbgv("WARNING: oops, making it not strict, but no idea what to do with this; mimetype is $mimetype");
			$strict = 0;
		}
		if (!$g_fluffmode) {
			$line = UserSpecifiedSubstitutions($line, $strict);
		}
		else {
			$line = FluffWork($line);
		}
		dbgvv("finished dousersubs stuff");
	}


	# finally, replace the marks with the files
	dbgvv("about to replace marks");
	my $markcnt2 = 0;
	while ($markcnt2 < $markcnt) {
		my $marksuf = FormatSuff($markcnt2);
		my $mark = "$stdmark$marksuf";
		my $file = $filerefs[$markcnt2];
		if (!($line =~s|$mark|$file|)) {
			dbg("ERROR: didn't replace $mark with $file, in $line");
		}
		$markcnt2++;
	}
	dbgvv("finished replacing marks");

	if ($line =~ /$stdmark/) {
		dbg("ERROR: unfortunately, still a $stdmark in $line");
	}

	# final hacks here, for javascript
	if ($g_givemedomain =~ /philipmorris/) {
		$line =~ s|(\+ ')\./(_)|$1$2|;
	}
				
	dbgvv("returning from DoMostSubs");		
	return $line;
}

sub checkimageerror {
	my ($fn, $errorcode) = @_;
	dbgv("checkimageerrror got $errorcode on $fn") if $errorcode;
	if ($errorcode == 404) {
		# if it's a broken image, replace it with an innocuous blank image
		if ( ($fn =~ /\.gif$/) || ($fn =~ /\.jpg$/) ) {
			dbgv("will replace $fn with pixel $g_pixelfile");
			$fn = "$basepath";
			# if ($g_cachedir) { # no...
			#	 $fn .= "/$g_cachedir";
			# }
			$fn .= "/$g_pixelfile";
			dbgv("   now fn is $fn");
		}
	}
	return $fn;
}
sub GetOutfile {
	# multiple temporary file possibilities--like three? that way, in case a file has a lingering lock 
	# that isn't real anymore, you can just go on and see if the next one is 
	# available, and the next... eventually the first will free itself for the 
	# next time it's attempted...
	my ($origsavefilenamepending) = @_;
	my $errorcode = 0;
	# See http://www.perlmonks.org/index.pl?node_id=7058&lastnode_id=102 for file locking tutorial.
	my $outfile = FileHandle->new();
	my $pendingsuff = 0;
	my $savefilenamepending;
	while (1) {
		$pendingsuff++;
		if ($pendingsuff > 4) {
			$errorcode = 505; # not the right code, but whatever
			dbgv("couldn't make the savefilenamepending, so returning with $savefilenamepending");
			last;
		}

		$savefilenamepending = "$origsavefilenamepending-$pendingsuff";
		my $pendingfileexisted = (-s $savefilenamepending);
		if ($pendingfileexisted) {
			unless ($outfile->open("+< $savefilenamepending")) {
				dbg("ERROR: couldn't open $savefilenamepending for read/write use: $@");
				next;
			}
		}
		else {
			unless ($outfile->open(">$savefilenamepending")) {
				dbg("ERROR: couldn't create file $savefilenamepending: $@");
				next;
			}
		}
		chmod $g_permissions, $savefilenamepending; # ???? what's this for????
		if (flock($outfile, 6)) { # LOCK_EX | LOCK_NB
			if ($pendingfileexisted) {
				dbgv("ALERT: WAS ABLE TO GET IMMEDIATE WRITE-LOCK, ".
					"but since $savefilenamepending existed, now we will truncate it");
				seek($outfile, 0, 0); # go to end of file
				truncate($outfile, 0); # truncate file
			}
			last;
		}
		else {
			flock($outfile, 8);
			$outfile->close(); # should use cleanup(0,0,0,0) but have that function check for outfile...
				# which i guess should be a global sometimes...
			dbgv("ALERT: CAN'T IMMEDIATELY WRITE-LOCK $savefilenamepending ($!), " .
				"so will increment suffix and try again");
			next;
		}
	}
	# dbgv("returning from GetOutfile with $savefilenamepending and errorcode $errorcode");
	return ($outfile, $savefilenamepending, $errorcode) 
}

sub printtoscreen {
	my ($mes) = @_;
	if (!($g_stubtype =~ /php/)) {
		print "Content-type: text/html\n\n"; 
	}
	print $mes;
}
# require "reamweaverlib.pl.disused.pl"; # these are unused functions
