package App::ZofCMS::Plugin::Captcha;

use warnings;
use strict;

our $VERSION = '0.0101';
use base 'App::ZofCMS::Plugin::Base';
use GD::SecurityImage;

sub _key { 'plug_captcha' }
sub _defaults {
    string  => undef,
    file    => undef,
    width   => 80,
    height  => 20,
    lines   => 5,
    particle => 0,
    no_exit => 1,
    style   => 'rect',
    format  => 'gif',
    tcolor  => '#895533',
    lcolor  => '#000000',
}
sub _do {
    my ( $self, $conf, $t, $q, $config ) = @_;

    my $image = GD::SecurityImage->new(
        width   => $conf->{width},
        height  => $conf->{height},
        lines   => $conf->{lines},
        gd_font => 'giant'
    );
    
    $image->random( $conf->{string} );
    $image->create('normal', @$conf{qw/style tcolor lcolor/} );

    if ( $conf->{particle} ) {
        $image->particle( ref $conf->{particle} ? @{ $conf->{particle} } : () );
    }
    
    my ( $image_data, $mime_type, $random_number ) = $image->out( force => $conf->{format} );
    $t->{d}{session}{captcha} = $random_number;

    if ( defined $conf->{file} and length $conf->{file} ) {
        if ( open my $fh, '>', $conf->{file} ) {
            binmode $fh;
            print $fh $image_data;
            close $fh;
        }
        else {
            $t->{t}{plug_captcha_error} = $!;
            return;
        }
    }
    else {
        binmode STDOUT;
        print "Content-Type: image/$mime_type\n\n";
        print $image_data;
        exit
            unless $conf->{no_exit};
    }
}

1;
__END__

=head1 NAME

App::ZofCMS::Plugin::Captcha - plugin to utilize security images (captchas)

=head1 SYNOPSIS

    plugins => [
        { Session => 1000 },
        { Captcha => 2000 },
    ],
    plugins2 => [
        qw/Session/
    ],

    plug_captcha => {},

    # Session plugin configuration (i.e. database connection is left out for brevity)

=head1 DESCRIPTION

The module is a plugin for L<App::ZofCMS> that provides means to generate and display
security images, known as "captchas" (i.e. protecting forms from bots).

The plugin was coded with idea that you will be using L<App::ZofCMS::Plugin::Session>
along with it to store the generated random string; however, it's not painfully
necessary to use Session plugin (just easier with it).

This documentation assumes you've read L<App::ZofCMS>, L<App::ZofCMS::Config> and L<App::ZofCMS::Template>

=head1 FIRST-LEVEL ZofCMS TEMPLATE AND MAIN CONFIG FILE KEYS

=head2 C<plugins>

    plugins => [
        { Session => 1000 },
        { Captcha => 2000 },
    ],
    plugins2 => [
        qw/Session/
    ],

B<Mandatory>. You need to include the plugin in the list of plugins to execute. I'm using
Session plugin here to first load existing session and after Captcha is ran, to save
the session.

=head2 C<plug_captcha>

    # all defaults
    plug_captcha => {},

    # set all arguments
    plug_captcha => {
        string  => 'Zoffix Znet Roxors',
        file    => 'captcha.gif',
        width   => 80,
        height  => 20,
        lines   => 5,
        particle => 0,
        no_exit => 1,
        style   => 'rect',
        format  => 'gif',
        tcolor  => '#895533',
        lcolor  => '#000000',
    },

    # or set some via a subref
    plug_captcha => sub {
        my ( $t, $q, $config ) = @_;
        return {
            string  => 'Zoffix Znet Roxors',
            file    => 'captcha.gif',
        }
    },

B<Mandatory>. Takes either a hashref or a subref as a value. If subref is specified,
its return value will be assigned to C<plug_captcha> as if it was already there. If
sub returns an C<undef>, then plugin will stop further processing.
The C<@_> of the subref will
contain (in that order): ZofCMS Tempalate hashref, query parameters hashref and
L<App::ZofCMS::Config> object. To run the plugin with all the defaults,
use an empty hashref. Possible keys/values for the hashref
are as follows:

=head3 C<string>

    plug_captcha => {
        string  => 'Zoffix Znet Roxors',
    },

B<Optional>. Specifies the captcha string. Takes either a scalar string or C<undef>.
If set to C<undef>, the plugin will generate a random numeric string. B<Defaults to:>
C<undef>.

=head3 C<file>

    plug_captcha => {
        file    => 'captcha.gif',
    },

B<Optional>. Takes either a scalar string or C<undef> as a value. If set to a string,
it represents the name of the file into which to save the captcha image (relative to
C<index.pl>). If set to C<undef>, plugin will output correct HTTP headers and the image
directly into the browser. B<Defaults to:> C<undef>.

=head3 C<no_exit>

    plug_captcha => {
        no_exit => 1,
    },

B<Optional>. This one is relevant only when C<file> (see above) is set to C<undef>.
Takes either true or false values. If set to a B<false value>, plugin will call
C<exit()> as soon as it finishes outputting the image to the browser. You'd use it
if you're generating your own string and are able to store it with the Session plugin
before Captcha plugin runs. If set to a B<true value>, plugin will not call C<exit()> and
the runcycle will continue; this way the Captcha plugin generated random string can
be stored by Session plugin later in the runlevel. B<Note:> that in this case, after the
image is printed the browser will also send some garbage (and by that I mean the
standard HTTP Content-type headers that ZofCMS prints along with whatever may be in
your template); even though I haven't noticed that causing any problems with the image,
if it does cause broken image for you, simply use L<App::ZofCMS::Plugin::Sub> and call
C<exit()> within it. B<Defaults to:> C<1>

=head3 C<width>

    plug_captcha => {
        width   => 80,
    },

B<Optional>. Takes a pisitive integer as a value. Specifies captcha image's width in pixels.
B<Defaults to:> C<80>

=head3 C<height>

    plug_captcha => {
        height  => 20,
    },

B<Optional>. Takes a pisitive integer as a value. Specifies captcha image's height in
pixels.B<Defaults to:> C<20>

=head3 C<lines>

    plug_captcha => {
        lines   => 5,
    },

B<Optional>. Specifies the number of crypto-lines to generate. See L<GD::SecurityImage> for
more details. B<Defaults to:> C<5>

=head3 C<particle>

    plug_captcha => {
        particle => 0, # disable particles
    },

    plug_captcha => {
        particle => 1, # let plugin decide the right amount
    },

    plug_captcha => {
        particle => [40, 50], # set amount yourself
    },

B<Optional>. Takes either false values, true values or an arrayref as a value. When set to an
arrayref, the first element of it is density and the second one is maximum
number of dots to generate - these dots will add more cryptocrap to your captcha. See
C<particle()> method in L<GD::SecurityImage> for more details. When set to a true value
that is not an arrayref, L<GD::SecurityImage> will try to determine optimal number of
particles. When set to a false value, no extra particles will be created.
B<Defaults to:> C<0>

=head3 C<style>

    plug_captcha => {
        style   => 'rect',
    },

B<Optional>. Specifies the cryptocrap style of captcha.
See L<GD::SecurityImage> C<create()> method for possible styles.
B<Defaults to:> C<rect>

=head3 C<format>

    plug_captcha => {
        format  => 'gif',
    },

B<Optional>. Takes string C<gif>, C<jpeg> or C<png> as a value. Specifies the format
of the captcha image. Some formats may be unavailable depending on your L<GD> version.
B<Defaults to:> C<gif>

=head3 C<tcolor>

    plug_captcha => {
        tcolor  => '#895533',
        lcolor  => '#000000',
    },

B<Optional>. Takes 6-digit hex RGB notation as a value. Specifies the color
of the text (and particles if they are on). B<Defaults to:> C<#895533>

=head3 C<lcolor>

    plug_captcha => {
        lcolor  => '#000000',
    },

B<Optional>. Takes 6-digit hex RGB notation as a value. Specifies the color
of cryptocrap lines. B<Defaults to:> C<#000000>

=head1 AUTHOR

'Zoffix, C<< <'zoffix at cpan.org'> >>
(L<http://haslayout.net/>, L<http://zoffix.com/>, L<http://zofdesign.com/>)

=head1 BUGS

Please report any bugs or feature requests to C<bug-app-zofcms-plugin-captcha at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-ZofCMS-Plugin-Captcha>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.


=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc App::ZofCMS::Plugin::Captcha

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-ZofCMS-Plugin-Captcha>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/App-ZofCMS-Plugin-Captcha>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/App-ZofCMS-Plugin-Captcha>

=item * Search CPAN

L<http://search.cpan.org/dist/App-ZofCMS-Plugin-Captcha/>

=back



=head1 COPYRIGHT & LICENSE

Copyright 2009 'Zoffix, all rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.


=cut

