# Simple chargen connection manager.
# Implements chargen and uses ReadWrite water
# marks to throttle its output.  Especially good
# for times when users with slow modems connect.
# Copyright 2004 by Rocco Caputo.  Free software.
# Same terms as Perl itself.  Have fun!

package Watermarks;

use warnings;
use strict;

use POE qw(Wheel::ReadWrite);

sub spawn {
  my ($class, $socket) = @_;

  POE::Session->create(
    inline_states => {
      _start       => \&handle_start,
      got_error    => \&handle_error,
      send_chunk   => \&handle_send,
      got_throttle => sub { },
      got_cts      => \&handle_cts,
    },
    args => [ $socket ],
  );
}

sub handle_start {
  my ($heap, $socket) = @_[HEAP, ARG0];
  $heap->{stream} = POE::Wheel::ReadWrite->new(
    Handle     => $socket,
    ErrorEvent => "got_error",
    HighMark   => 8192,
    LowMark    => 4096,
    HighEvent  => "got_throttle",
    LowEvent   => "got_cts",
  );

  $heap->{start_ascii} = 32;
  $_[KERNEL]->yield("send_chunk");
}

sub handle_error {
  my $heap = $_[HEAP];
  my ($syscall, $errno, $text) = @_[ARG0..ARG2];
  delete $heap->{stream};
  return unless $errno;
  warn "Conn: $syscall error $errno: $text\n";
}

sub handle_send {
  my $start_ascii = $_[HEAP]->{start_ascii};

  while (1) {
    my $next_line = generate_line(\$start_ascii);
    last if $_[HEAP]->{stream}->put($next_line);
  }

  $_[HEAP]->{start_ascii} = $start_ascii;
}

sub handle_cts {
  print(
    "Client ok to send again ", scalar(localtime),
    "\n"
  );
  goto &handle_send;
}

sub generate_line {
  my $start_ascii = shift;
  my $chargen_line = join(
    '',
    map { chr }
    ($$start_ascii ..  $$start_ascii + 71)
  );
  $chargen_line =~ tr[\x7F-\xDD][\x20-\x7E];
  $$start_ascii = 32 if ++$$start_ascii > 126;
  return $chargen_line;
}

1;
