#!/usr/bin/perl

use CGI;
use Socket;
#use warnings;

# Change this if you move the gateway. Duh. :-) - nocturne
# url_retrieve currently uses a handler for SIGALRM.  take that out if
# you turn this one on (since the other one will kill this one) - gemery
$SIG{'ALRM'} = 'alarmhandler';
alarm(10);
$our_base_url = "/tweb";
$logfile = '/var/tmp/trans-log';
$errorfile = '/var/tmp/trans-error';
$tmpdir  = '/var/tmp';

# the next statement nices this process's priority to 4.  The last
# argument is the priority.
# note: setpriority won't work under Solaris.

#setpriority(&PRIO_PROCESS,0,4);

$file_bin = '/usr/bin/file';

$| = 1;
open(STDERR,">>${errorfile}");

$query = join(' ', @ARGV) if $ARGV[0];


&do_trans($query);

### main part: decide what we're doing...

sub do_trans {
    local($query) = @_;
    local($pathinfo, $post, $querystr);
    $args =~ s/\+/ /g;
    $pathinfo = $ENV{PATH_INFO};
    $post = 0;
    $postquery = "";
    
# time checks disabled on an experimental basis (gemery, 7/22/1999)
#    &checktime();
    
    if (! $ENV{'SERVER_PROTOCOL'}) {
         &old($query);
    } else {
        if($ENV{'REQUEST_METHOD'} eq "GET") {
           $querystr = $ENV{'QUERY_STRING'};
           $post = 0;
        } elsif($ENV{'REQUEST_METHOD'} eq "POST") {
           read(STDIN, $querystr, $ENV{'CONTENT_LENGTH'});
           $post = 1;
        }

        if ($pathinfo =~ m"^/form\.html") {
            if($post) {
                # the form uses GETs, you can't post to it
                &not_found();
            } elsif ($querystr ne "") {
		# they are submitting a form-based transparentizing query.
                &trans_form_parse($querystr);
            } else {
		# They are requesting the first-level form.
                &trans_form();
            }
        } elsif ($pathinfo =~ m"^/map\.html") {
            if($post) {
		# They are requesting the intermediate transparentization
		# imagemap-based form.
                &trans_map_parse($querystr);
            } elsif($querystr ne "") {
                # no submitting form data with a GET
                &not_found();
            } else {
		# They are requesting the first-level imagemap form.
                &trans_map();
            }
	} elsif ($pathinfo =~ m"^/map-parse/(.*)$") {
	    $pathinfo = $1;
            if ($querystr eq "") {
		# this url should only be retrieved with image map coords
                &not_found();
            } else {
		# They are submitting an imagemap-based transparentizing query
                &map_transparent($pathinfo, $querystr);
            }
        } else {
            &not_found();
	}
    }

    &kill_parent();
    exit(0);
}

sub map_transparent {
    local($encoded_url, $location, $url, $tempfile) = @_;
    local($their_url) = &decode_url($encoded_url);
    local($image_data, $result_code, $result_message) = &url_retrieve($their_url);
    # success http result codes start with 2
    unless($result_code >= 200 && $result_code < 300) {
        &log_url($their_url, "map", $result_message);
	&you_suck($result_code);
	return 0;
    }

    $tempfile = ($tmpdir . "/www_trans.$$");

    open(IMAGE, ">$tempfile");
    print IMAGE $image_data;
    close(IMAGE);

    $file_type = (split(/:\s*/, `$file_bin $tempfile`, 2))[1];
    if($file_type =~ /GIF/) {
# giftoppm doesn't like interlaced gifs
	open(GIFTOPPM, "| /usr/bin/convert - ppm:- > $tempfile");
	print GIFTOPPM $image_data;
	close(GIFTOPPM);

	$color = "#" . &get_color($tempfile, $location);

        open(IMAGE, ">$tempfile");
        print IMAGE $image_data;
        close(IMAGE);

        # MIME headers
        print "Content-type: image/gif\n";
        #&mime_transient();
        print "\n";
        open(CONVERT, "/usr/bin/convert -transparent '$color' $tempfile -|");
	while (<CONVERT>) {
	    print $_;
	}
        close(CONVERT);
	unlink($tempfile);
	return 1;
    } else {
        &log_url($their_url, "map", $file_type);
	&nongifs_suck($file_type);
	unlink($tempfile);
	return 0;
    }
}

sub transmogrify {
    local($url, $color) = @_;
    local($image_data, $result_code, $result_message) = &url_retrieve($url);
    local($file_type);


    # success http result codes start with 2
    unless($result_code >= 200 && $result_code < 300) {
        &log_url($remote_url, "form", $result_message);
	&you_suck($result_code);
	return 0;
    }

    # create a (practically) unique filename into which to
    # temporarily stuff data.
    $tempfile = ($tmpdir . "/www_trans.$$");

    open(IMAGE, ">$tempfile");
    print IMAGE $image_data;
    close(IMAGE);

    $file_type = (split(/:\s*/, `$file_bin $tempfile`, 2))[1];

    if($file_type =~ /GIF/) {

        &log_url($remote_url, "form", "OK");

        # MIME headers
        print "Content-type: image/gif\n";
        #&mime_transient();
        print "\n";

        open(CONVERT, "/usr/bin/convert -transparent '$color' $tempfile - |");
	while (<CONVERT>) {
	    print $_;
	}

	close (CONVERT);

	unlink($tempfile);
	return 1;

    } else {

        &log_url($remote_url, "form", $file_type);
        &nongifs_suck($file_type);
        #unlink($tempfile);
        return 0;

    }
}

# this routine takes a url and attempts to retrieve the data from it.
# it returns an array of ($data, $result_code, $result_message) where data 
# is the data retrieved, result_code is the HTTP code from the server, and
# result_message is some string describing the error that occurred.
# result_code will be negative if another error occurred
# -1: some error in parsing the url
# -2: some error connecting to the remote server
# -3: transfer timed out because it took too long
# 2*: ok
# 3*: redirect
# 4*: doesn't exist/permission denied
# 5*: server error

# we only support http requests for now

sub url_retrieve {
   local($url, $redirect_count) = @_;
   local($service, $host, $port, $path, $null, $code, $message, $pid);
   local($newurl);
   local(@data);
   local($oldfh);

# assume 0 if no second argument was passed
   $redirect_count = 0 unless defined($redirect_count);

   return(undef, -2, "too many redirects") if $redirect_count > 5;

# parse out the url for service, host, port, and path
   $url =~ m|^([\w]+)://([a-zA-Z0-9.\-]+)(:(\d+))?(/.*)$| || return (undef, -1, "parse error");
   ($service, $host, $port, $path) = ($1, $2, $4, $5);

   return (undef, -1, "'$service' request not supported") unless $service eq "http";

   $port = 80 if $port eq "";

# The server will only make connections to a small number of ports so
# that it can't be effectively misused as a port-scan proxy. These
# are all of the ports that were used over a one-year period (other
# than ports on web servers that aren't still around). Port 2784 was
# not actually used but it's a registered www-development port.
   if ($port != 80 and $port != 81 and $port != 88 and $port != 2001
       and $port != 2784 and $port != 8001 and $port != 8030
       and $port != 8080 and $port != 10021) {
       return (undef, -4, "'$service' request not supported");
   }

# incantation for summoning a socket
   $iaddr = inet_aton($host) or return (undef, -2, "host not found");
   $paddr=sockaddr_in($port, $iaddr);
   $proto=getprotobyname('tcp');
   socket(S, PF_INET, SOCK_STREAM, $proto) or return (undef, -2, $!);

# this little block sets a SIGALRM handler so we can time out the connection
# attempt after 2 minutes
   eval {
      $SIG{'ALRM'} = "url_alrm_handler";
      alarm 120;           # i fear any image that takes longer than two
                           # minutes to download

      connect(S, $paddr) or die "$!\n";

# make the socket unbuffered.  trust me.
      $oldfh = select(S); $| = 1; select($oldfh);

      print S "GET $path HTTP/1.0\nHost: $host\n\n";
      @data = <S>;
      close(S);
      
      alarm 0;
   };

# if there was an error, determine what it was
   if($@) {
      close(S);
      if($@ =~ /alarm/) {
         return (undef, -3, "transfer timed out");
      } else {
         return (undef, -2, $@);
      }
   }

# get the http respose code
   ($null, $code, $message) = split(/\s+/, $data[0], 3);
# kill carriage returns and line feeds
   $message =~ tr/\r\n//d;

# handle redirects
   if($code >= 300 && $code < 400) {
# find the line that tells us where to go next
      shift @data until $data[0] =~ /^Location:\s*(\S*)/i;
      $newurl = $1;
      return &url_retrieve($newurl, $redirect_count + 1);
   }

# dump all lines upto the first blank one
   shift @data while(@data && $data[0] !~ /^[\r\n]*$/);

   return(join('', @data[1..$#data]), $code, $message);
}

sub url_alrm_handler {
   die "alarm\n";
}

### remove \000-\039 and \177-\377

sub prot {
    $_[0] =~ s/[\000-\037\177-\377]+//g;
    $_[0];
}

### parsing data
#
#   the POST data is all packed in the form
#      field1=value1&field2=value2&...
#   with the "invalid" characters encoded as %-sequences.

sub trans_map_parse {
    local(%post, $tmp, $name);

    for (split(/&/,$_[0])) {
	if (/=/) {
	    $name = $`;
	    $tmp = $';
	    $tmp =~ s/\+/ /g;
	    $tmp =~ s/%([\da-f]{1,2})/pack(C,hex($1))/eig;
	    $post{$name} = $tmp;
	}
    }

    $their_url = &prot($post{'dullimage'});

    print "Content-Type: text/html\n\n";
    print "<html>\n<head>\n<title>TransWeb";
    print "</title>\n</head><body>\n";
    print "<h1>TransWeb</h1>\n";
    print "<h2>Transparentizing Clickable Imagemap</h2>\n";
    print "You should click on a place in this image which is the color\n";
    print "you'd like to make transparent.<p>\n";
    print "<a href=\"" . CGI->escapeHTML($our_base_url) . "/map-parse/";
    print CGI->escapeHTML(&encode_url($their_url)) . "\">";
    print "<img align=middle src=\"" . CGI->escapeHTML($their_url) . "\" ISMAP></a>\n";
    print "<p>\nYou should also note that this web page was generated\n";
    print "on the fly -- attempts to reload this page or return to this\n";
    print "page by copying down its URL will only get you the top-level\n";
    print "web page.<p>\n";
    print "<hr>\nIf you have any problems with this, feel free to\n";
    print "<a href=\"/comment\">send mail to\n";
    print "stuffmaster\@mit.edu</a> about it.\n</body>\n</html>\n";
}

sub trans_form_parse {
    local(%post, $tmp, $remote_url, $name, $red, $green, $blue, $base);

    for (split(/&/,$_[0])) {
	if (/=/) {
	    $name = $`;
	    $tmp = $';
	    $tmp =~ s/\+/ /g;
	    $tmp =~ s/%([\da-f]{1,2})/pack(C,hex($1))/eig;
	    $post{$name} = $tmp;
	}
    }

# to prevent people from linking to transparentized images, we use the 
# hidden field 'sq' in the form to determine how old the request is.
# requests from more then 600 seconds (10 minutes) ago are refused.  a clever
# person could circumvent this, but i don't think that's a serious risk,
# esp with most of our use coming from webtv ;)
    if($post{'sq'} > time || time - $post{'sq'} > 600) {
        &time_bounds();
        return 0;
    }

    $remote_url = &prot($post{'dullimage'});
    $red        = &prot($post{'red'});
    $blue       = &prot($post{'blue'});
    $green      = &prot($post{'green'});
    $base       = &prot($post{'base'});

    if ($base eq "Hexidecimal") {
	# this cuts out unnecessary resolution and converts to decimal.
	$red   = hex(substr($red,   0, 2));
	$green = hex(substr($green, 0, 2));
	$blue  = hex(substr($blue,  0, 2));
    }

    # This converts (back) to hexidecimal, and pads with "0"s.
    $red   = sprintf("%02x", $red);
    $green = sprintf("%02x", $green);
    $blue  = sprintf("%02x", $blue);

#    print("Content-Type: image/gif\n\n");

    $color = "#" . $red . $green . $blue;

    &transmogrify($remote_url, $color);

}

### error message for attempted use with HTTP/0.9 and earlier
sub old {
    local($args) = @_;

    print <<"EndOfStuff";
Content-Type: text/html\n\n
<title>TransWeb gateway on WWW.MIT.EDU</title>
<h1>Your client is old...</h1>

Your client does not support HTTP/1.0, and therefore can't use the
form support interface. We suggest you ask your system administrator
to install a more recent web client.<p>

We're sorry, but we really can't provide an interface you can use.
If you would like to talk with us about this, feel free to
<a href="/comment">send mail to
stuffmaster\@mit.edu about it</a>.
EndOfStuff
}

# this page should not be cached since it contains a time stamp.  things
# will break horribly and inexplicably if that doesn't get reset every
# time the page is viewed
sub trans_form {
    local($cur_time) = time;

    &mime_transient();
    print("Content-Type: text/html\n\n");
    print("<html>\n<head><title>TransWeb Transparent-GIF Service</title>\n");
    print("</head><body>\n");
    print("<h1><a href=\"/transweb.html\">TransWeb");
    print("</a></h1>\n");

    print <<"EndOfForm";
<h2>Helping you to make Transparent Images</h2>

This gateway allows you to enter the URL of a GIF image, and a colormap entry
to be made transparent. When you submit this form, TransWeb will read the
image you specified and return to you a transparentized version of the image.
<p>

If you have a web browser which supports clickable imagemaps (e.g.
Mosaic, Arena), you may find the
<a href="$our_base_url/map.html">imagemap-based
version of TransWeb</a> easier to use.<p>

<img align="bottom" alt="**NOTE**" src="/gif/info.gif">
It is highly likely that you will want to configure your browser to
"load to disk" before you submit this form, if it is configured to spawn
a separate image-viewing program when receiving images. (In Mosaic,
you can do this by selecting "Load to Local Disk" from the "Options" menu.)
<p>

<hr>

Please:
<ul>
<li>specify the URL of the image you'd like to transparentize
<li>specify the RGB value of the color to be transparentized
<li>select the base in which you are specifying the RGB values: hexidecimal
(base 16) or decimal (base 10).
</ul>

<hr>

<FORM method="GET">
Image URL: <input name="dullimage" size=50><p>

<ul>
<li>Red:<input name="red" size=8><br>
<li>Green:<input name="green" size=8><br>
<li>Blue:<input name="blue" size=8><br>
</ul>

<input type="radio" name="base" value="Decimal"    >Decimal<br>
<input type="radio" name="base" value="Hexidecimal" CHECKED>Hexidecimal<p>

<input type="hidden" name="sq" value="$cur_time">

<input type="submit" value="Submit these values">
<input type="reset" value="Naaaaah, just kidding">
</FORM>
EndOfForm

    &print_std_footer();
}

sub trans_map {
    &print_std_header();

    print <<"EndOfForm2";
<h2>Helping you to make Transparent Images</h2>

If your web browser is incapable of handling imagemaps (e.g. lynx,
emacs w3-mode, CERN linemode browser), then you will be unable to make use
of the form on this page. However, there is hope. You can use the
<a href="$our_base_url/form.html">form-based version of TransWeb</a>,
which allows you to specify colors via HTML forms, rather than
by clicking on an image.<p>

This gateway allows you to specify the URL of a GIF image which you'd
like to transparentize:

<ol>

<li>When you submit this form, TransWeb will present you with an
imagemap.

<li><em>After you submit the form on this page</em>, you should configure
your web browser to load the next retrieved URL to local disk. (In Mosaic,
you can do this by selecting "Load to Local Disk" from the "Options" menu.)

<li>You should click on the spot on the imagemap you'd like to make
transparent.

<li>TransWeb will return to you a transparentized version of the
image you specified.

</ol>

<hr>

<FORM method="POST">
Image URL: <input name="dullimage" size=50><p>

<input type="submit" value="Submit this URL">
<input type="reset" value="Naaaaah, just kidding">
</FORM>
EndOfForm2
   &print_std_footer();
}

sub not_found {
    print("Content-Type: text/html\n\n");

    print <<"EndOfForm3";
<html><head>
<title>Not Found</title>
</head><body>
The URL you specified was not found. Perhaps you're looking for one of
these:
<ul>

<li>our <a href="$our_base_url/map.html">clickable-imagemap-based
transparentizing service</a>

<li>our <a href="$our_base_url/form.html">form-based transparentizing service</a>
</ul></body></html>
EndOfForm3
}
1;

sub nongifs_suck {
    local($file_type) = @_;

    print <<EOM;
Content-type: text/html

<html><head>
<title>Error</title>
</head>
<body>
EOM
    if($file_type =~ /JPEG/) {
       print <<EOM;
The image at the URL you specified appears to be a JPEG.  Unfortunately, 
this service only works on GIFs, but you can convert your image to a GIF
and try again.
EOM
    } else {
       print <<EOM;
The image at the URL you specified does not seem to be a GIF.
Unfortunately, this service only works on GIFs, but you can convert 
your image to a GIF and try again.
EOM
    }

    &print_std_footer();
}

sub you_suck {
    local($result_code) = @_;

    print <<EOM;
Content-type: text/html

<html><head>
<title>Error</title>
</head>
<body>
TransWeb was unable to retrieve the image you specified because
EOM
    if($result_code == -1) {
        print "the URL you specified was not valid.  Note that TransWeb only supports HTTP URLs; support for FTP URLs has not been implemented yet.\n";
    } elsif($result_code == -2) {
	print "it could not connect to the web server you specified.\n";
    } elsif($result_code == -3) {
	print "the connection timed out while transferring the image.\n";
    } elsif($result_code == -4) {
	print "the URL you specified was not valid.  Note that TransWeb will only make HTTP connections to standard web-server ports (e.g., port 80).  If there is another port number that you believe should be supported, you can request it by sending e-mail to stuffmaster\@mit.edu mentioning TransWeb and that port number.  New ports are added only occasionally, so please be patient.\n";
    } elsif($result_code >= 400 && $result_code < 500) {
	print "the URL you specified was not found on that server, or Transweb is not allowed to access it\n";
    } else {
	print "an unknown error occurred while downloading.\n";
    }

    print "Check to make sure you entered the URL correctly and try again.\n";

    &print_std_footer();
}

# prints out mime headers that should prevent all but the stupidest web
# browsers from caching these pages
sub mime_transient {
    local($curdate) = &httpdate();

    print "Cache-control: no-cache\n";
    print "Date: $curdate\n";
    print "Expires: $curdate\n";
}

sub print_std_header {
    print("Content-Type: text/html\n\n");
    print("<html>\n<head><title>TransWeb Transparent-GIF Service</title>\n");
    print("</head><body>\n");
    print("<h1><a href=\"/transweb.html\">TransWeb");
    print("</a></h1>\n");
}

sub time_bounds {
    print <<EOM;
Content-type: text/html

<html><head><title>Error</title></head>
<body>
Sorry, your request could not be completed.  You will need to go back to 
the <A HREF="$our_base_url/form.html">form</A> or the 
<A HREF="$our_base_url/map.html">image map</A> and resubmit your query.
EOM
    &print_std_footer();
}

sub print_std_footer {
print <<"EndOfFooter";
<hr>

Related pages which might be of interest:

<ul>
<li><a href="/transweb.html">TransWeb Homepage</a>
<li><a href="/people/nocturne/transparent.html">Nocturne's
Transparent Image page</a>
<li><a href="/sipb-homepage.html">MIT SIPB Web-server Homepage</a>
</ul>

<hr>

Feel free to <a href="/comment">send mail to
stuffmaster\@mit.edu</a> if you have any questions or problems.<p>

The TransWeb service was written by 
<a href="/people/nocturne/homepage.html">Eric
Mumpower (nocturne)</a>.<p>

EndOfFooter
}


sub get_color {
    local($filename, $position, $x, $y, $height, $width, $placeflag,
	  $raw_format, $goalpix, $line, $curpix, $pixel) = @_;

    if ($position =~ /(\d*),(\d*)/) {
        $x = $1;
        $y = $2;
    } else {
        print "Content-Type: text/html\n\n";
        print "Something went wrong. We didn't get the imagemap\n";
        print "coordinates. Sorry, you lose.\n";
	return;
    }

    open(IMAGE, ("<" . $filename));

    $placeflag  = 0;
    $raw_format = 0;

    # Read the ppm manpage for a specification of this format.
    until ($placeflag == 4) {
	$line = <IMAGE>;

	# "#" is the comment character.
	$line =~ s/#.*$//;

	# this means we haven't hit the magic number yet
	if ($placeflag == 0) {
	    if ($line =~ s/P(\d)\s*//) {
	        $raw_format = $1;
		if ($raw_format =~ "6") {
                    $raw_format = 1;
                } else {
                    $raw_format = 0;
                }

	        $placeflag = 1;
	    }
        }

	# this means we haven't hit the width yet
	if ($placeflag == 1) {
	    if ($line =~ s/(\d+)//) {
	        $width = $1;
		$placeflag = 2;
	    }
	}

	# this means we haven't hit the height yet
	if ($placeflag == 2) {
	    if ($line =~ s/(\d+)//) {
	        $height = $1;
		$placeflag = 3;
		$goalpix = ($x + ($width * $y));
		if ($goalpix < 1) {
		    $goalpix = 1;
		}
		if ($goalpix > ($width * $height)) {
		    $goalpix = ($width * $height);
                }
	    }
	}

	# this means we haven't hit the maxval yet
	if ($placeflag == 3) {
	    if ($line =~ s/(\d+)//) {
	        $maxval = $1;
		$placeflag = 4;
	    }
	}

	if ($placeflag == 4) {
	    if ($raw_format) {
	        if ($line !~ /^\s*$/) {
		    #oh shit, they put data on the line with the maxval.
		    $line =~ s/\s//g;
		    $curpix = length($line) / 3;
		    if ($goalpix < $curpix) {
			return(substr($line, $goalpix * 3, 3));
		    }
		}
	    } else { # else not in raw format
		# I'm not writing code for this because I think it won't
		# happen, because GIFs are 8-bit.
		if ($line !~ /^\s*$/) {
		    &we_suck();
        	    return;
		}
	    }
	}
    }

    if ($raw_format) {
	# We can assume that it's byte number (n), from this point.
	seek(IMAGE, (3 * ($goalpix - 1)), 1);
	read(IMAGE, $pixel, 3);

	return(sprintf("%02x%02x%02x", (unpack("C3", $pixel))));

    } else {
	&we_suck();
        return;
    }
}

sub we_suck {
    print "Content-Type: text/html\n\n";
    print "<p>Sorry, due to shortcomings in our software, we cannot\n";
    print "process your request. Please don't send us mail about\n";
    print "this; we know there is a problem, and are rewriting the\n";
    print "software as we find the time.\n</p>";
}

sub checktime {
    local($hour);

## this code should only be uncommented for debugging purposes
##   return if($ENV{'REMOTE_ADDR'} =~ /^18\./);
##   &kill_parent();
##   exit;
##

    $hour = (localtime)[2];

    if (($hour > 11) && ($hour < 18)) {
        print <<"END";
Content-Type: text/html

<html><head><title>Try again later...</title></head>
<body><h1>Try TransWeb later...</h1>

The TransWeb service has been disabled during peak usage hours (12 pm
- 6 pm EST) due to excessive server load. Please try it again outside
these hours.<p>

<hr>
<address><a href="/comment">stuffmaster\@mit.edu</a></address>
</body></html>
END
        &kill_parent();
	exit;
    }
}

sub cooldate {
    local(@t, $year, $month, $day);
    @t = localtime();
    $year  =  $t[5];
    $month = ($t[4] + 1);
    $day   =  $t[3];
    return &padzero($year) . &padzero($month) . &padzero($day);
}

# this routine returns the current date and time in GMT as per RFC 822.  this
# is what is expected in an Expires: field in an http response header
sub httpdate {
    local(@t, $wday, $mname);

    @t = gmtime();
    $wday = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")[$t[6]];
    $mname = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")[$t[4]];

    return sprintf("%s, %02d %s %d %02d:%02d:%02d GMT", $wday, $t[3], $mname, $t[5], $t[2], $t[1], $t[0]);
}

sub fulldate {
    local(@t, $year, $month, $day, $date);
    @t = localtime();
    $year  =  $t[5];
    $month = ($t[4] + 1);
    $day   =  $t[3];
    $date = &padzero($year) . "/" . &padzero($month) . "/" . &padzero($day);
    $time = &padzero($t[2]) . ":" . &padzero($t[1])  . ":" . &padzero($t[0]);

    return $date . " " . $time;
}

sub padzero {
    local($n) = @_;
    ($n<10)?("0" . $n):$n;
}

sub encode_url {
    local($url) = @_;
    local($cdate, $crypts);
    $cdate = &cooldate();

    # encrypt with today as the key
    $crypts = my_crypt($cdate,$url);

    # uuencode
    $crypts = pack("u", $crypts);

    # %00-encode URL-unsafe characters
    # Reserve A as character to change "%" to.
    $crypts =~ s/([^a-zB-Z0-9\.])/sprintf('%%%02x',ord($1))/eg;

    # Change "%" to "A"
    $crypts =~ s/\%/A/g;
    return ($crypts);
}

sub decode_url {
    local($crypts) = @_;
    local($cdate);
    $cdate = &cooldate();

    # Change "A" to "%"
    $crypts =~ s/A/\%/g;

    # Decode the webified %00-style encodings
    $crypts =~ s/%([\da-f]{1,2})/pack(C,hex($1))/eig;

    # uudecode
    $crypts =  unpack("u", $crypts);

    # decrypt, using today as the key.
    $crypts = &my_decrypt($cdate, $crypts);

    return ($crypts);
}

sub my_crypt {
    local($key, $string) = @_;

    $key =~ s/^.*(.)$/$1/;

    for($n=0; $n < $key; $n++) {
        $string =~ tr/a-zA-Z0-9\.\/\:/ZA-Y0-9\.\/\:a-z/;
    }

    return $string;
}

sub my_decrypt {
    local($key, $string) = @_;

    $key =~ s/^.*(.)$/$1/;

    for($n=0; $n < $key; $n++) {
        $string =~ tr/ZA-Y0-9\.\/\:a-z/a-zA-Z0-9\.\/\:/;
    }

    return $string;
    print "Mime-type: text/html\n\n";
    print "$key\n";
    exit(0);
}


# this expects the url the hit came from, the mode the transparentizer was
# operating in at the time ("map" or "form" as of this writing), and some
# string which indicates how successful the operation was
sub log_url {
    local($url, $mode, $result_code) = @_;

# kill any newlines in $result_code
    $result_code =~ tr/\r\n//d;

    open (LOG, ">>" . $logfile);
    print LOG (&fulldate() . " [$ENV{'REMOTE_ADDR'}] ($mode) $url (result: $result_code)\n");
    close LOG;
}

sub kill_parent {
    if ($forking == 1) {
	kill 9, getppid();
    }
}

sub alarmhandler {
    close(S);
    unlink("$tmpdir/www_trans.$$");
    print("Timed out.  Goodbye\n");
    exit;
}

1;
