# Copyright 2002-2008 Josh Clark and Global Moxie, LLC. This code cannot be 
# redistributed without permission from globalmoxie.com.  For more
# information, consult your Big Medium license.
#
# $Id: Email.pm 3236 2008-08-21 14:30:44Z josh $

package BigMed::App::Web::Email;
use Carp;
$Carp::Verbose = 1;
use strict;
use utf8;
use base qw(BigMed::App::Web::Public);
use BigMed::Email;
use BigMed::Site;
use BigMed::Content::Page;
use BigMed::Format::HTML;    #to load prefs
use BigMed::Filter;
use BigMed::NoBots (
    'antispam_referrer_match', 'confirm_captcha_response',
    'query_antispam_fields',
    'antispam_display_info',   'get_captcha_html',
    'is_form_fresh',
);
use BigMed::PageUtils;

sub setup {
    my $app = shift;
    $app->start_mode('email-page');
    $app->run_modes(
        'AUTOLOAD'   => sub { $_[0]->rm_email_page() },
        'email-page' => 'rm_email_page',
    );
}

sub rm_email_page {
    my $app = shift;

    my $site_id = $app->path_site;
    my ( $sec, $pid, $author ) = $app->path_args;
    $author    ||= '';
    $pid       ||= '';
    $pid       =~ s/\D+//g;
    $site_id   =~ s/\D+//g;

    #fetch site and page objects
    my ( $site, $page );
    if (   !$pid
        || !$site_id
        || !$sec
        || !( $site = BigMed::Site->fetch($site_id) )
        || !(
            $page =
            BigMed::Content::Page->fetch( { site => $site_id, id => $pid } )
        )
        || $page->pub_status ne 'published'
      )
    {
        $app->set_error(
            head => 'EMAIL_Could not determine page',
            text => 'EMAIL_TEXT_Could not determine page',
        );
        return $app->error_stop;
    }

    #get author id
    my $author_id;
    if ( $author =~ /author(\d+)/ ) {
        ($author, $author_id) = ('author', $1);
    }
    if ( $author eq 'author' && !$author_id ) {
        $app->set_error(
            head => 'EMAIL_Could not determine author',
            text => 'EMAIL_TEXT_Could not determine author',
        );
        return $app->error_stop;
    }

    #coming from a valid-ish url?
    my $page_url = $page->page_url( $site, { section => $sec } );
    my $dot = $app->env('DOT');
    my $refer_ok = $app->antispam_referrer_match( $page, "${dot}email" )
      || $app->antispam_referrer_match($page)
      || $app->_referrer_commentcgi_match;
    return $app->return_to_page($page_url)
      if !$app->require_post || !$refer_ok;

    #gather field names (if coming from cgi, could be resubmit request,
    #let it through with short min_seconds time)
    my $min_seconds = $refer_ok eq 'cgi' ? 2 : undef;
    my @fields = qw(id formfrom formmsg);
    push @fields, 'formto' if $author ne 'author';
    my $rfield = $app->query_antispam_fields(
        $page,
        {   fields      => \@fields,
            min_seconds => $min_seconds,
        }
      )
      or return $app->return_to_page($page_url);
    my %fieldname = %{$rfield};

    #confirm id match, and gather fields
    return $app->return_to_page($page_url)
      if $app->utf8_param( $fieldname{id} ) != $pid;
    my @collect = (
        {   id       => $fieldname{formfrom},
            parse_as => 'email',
            required => 1,
        },
        {   id       => $fieldname{formmsg},
            parse_as => 'raw_text',
        },
        {   id       => 'bmf_cc',
            parse_as => 'boolean',
        },
    );
    if ( $author ne 'author' ) {
        unshift @collect,
        {   id       => $fieldname{formto},
            parse_as => 'email',
            required => 1,
        },
    }
    my %field = $app->parse_submission(@collect);

    #check fields and show field if there's a hitch
    my $caught_error = !$app->confirm_captcha_response( $site, $page )
      || $field{_ERROR};
    if ( !$app->is_form_fresh($page) ) {    #form is older than 30 minutes
        $caught_error = 1;
        $app->set_error(
            head => 'NOBOTS_Timeout',
            text => 'NOBOTS_TEXT_Timeout',
        );
    }
    if ($caught_error) {                    #give the form again
        return $app->retry(
            site       => $site,
            sec_id     => $sec,
            page       => $page,
            fieldnames => \%fieldname,
            field_msg  => $field{_ERROR},
        );
    }

    #all clear from antispam measures...
    my $from_mail = $field{ $fieldname{formfrom} };
    my $message = $field{ $fieldname{formmsg} };
    my ( $to_mail, $subject, $intro );

    #grab the author if applicable
    if ( $author eq 'author' ) {
        my @people = $page->load_related_objects('author');
        $app->error_stop if $app->error;
        my $author;
        foreach my $pair (@people) {
            $author = $pair->[1], last if $pair->[1]->id == $author_id;
        }
        if ( !$author ) {
            $app->set_error(
                head => 'EMAIL_Author Mismatch',
                text => 'EMAIL_TEXT_Author Mismatch',
            );
            return $app->error_stop;
        }
        $to_mail = $author->email;
        if ( !$to_mail ) {
            $app->set_error(
                head => 'EMAIL_No Author Email',
                text => [
                    'EMAIL_TEXT_No author email',
                    $author->first_name . ' ' . $author->last_name
                ],
            );
            return $app->error_stop;
        }

        $subject = $site->get_pref_value('html_emailform_textsubjectauthor');
        $intro = $site->get_pref_value('html_emailform_textintroauthor');
        if ( !$subject || !$intro ) { #hmm i/o error on site, subject or intro
            $subject = $app->language('EMAIL_Author subject');
            $intro   = $app->language('EMAIL_Author intro');
        }
    }
    else {
        $to_mail = $field{ $fieldname{formto} };
        $subject = $site->get_pref_value('html_emailform_textsubject');
        $intro   = $site->get_pref_value('html_emailform_textintro');
        if ( !$subject || !$intro ) { #hmm i/o error on site, subject or intro
            $subject = $app->language('EMAIL_Email This subject');
            $intro   = $app->language('EMAIL_Email This intro');
        }
    }
    
    #format the site name and article title and text
    my $site_name = $site->name;
    my $title = $app->strip_html_tags( $page->title );
    my $desc  =
      $app->strip_html_tags( BigMed::Filter->filter( $page->description ) );
    foreach ( $title, $desc, $site_name ) {
        $_ = $app->unescape($_);
        $_ =~ s/&nbsp;/ /g;
        $_ =~ s/\s+/ /g;
    }
    my $msg_intro = $site->get_pref_value('html_emailform_textsendermsg');
    foreach ($subject, $intro, $msg_intro) {
        $_ =~ s/<%sitename%>/$site_name/g;
    }
    
    my $return_url = $page_url;
    $return_url =~ s/[.]shtml(\?.*|$)/${dot}email.shtml?sent/;

    $page_url =~ s/~/\%7E/msg;
    my $title_and_desc = $desc ? "$title\n$desc" : $title;
    $message   = <<"EMAIL_MSG";
$intro
$from_mail

-----------------------------

$title_and_desc

$page_url

-----------------------------

$msg_intro
$message
EMAIL_MSG

    BigMed::Email::send_email(
        from    => $from_mail,
        to      => $to_mail,
        cc      => $field{bmf_cc} ? $from_mail : undef,
        subject => $subject,
        body    => $message
      )
      or $app->error_stop;

    my $redirect = $return_url;
    $app->header_type('redirect');
    $app->header_props( -url => $redirect );
    "Redirecting to $redirect";
}

sub retry {
    my $app    = shift;
    my %option = @_;
    my ( $sec_id, $pid, $author ) = (my @args = $app->path_args );
    my ( $site, $page, $roldfield ) =
      @option{qw(site page fieldnames)};
    my %oldfield = %{$roldfield};
    my %lookup   = reverse %oldfield;

    my %display_info =
      $app->antispam_display_info( $page,
        [qw(id formto formfrom formmsg)],
        { no_include => 1 });
    my %realname = %{ $display_info{realname} };
    my %fakename = %{ $display_info{fakename} };

    #revise field_msg errors and query values for new field names
    my %err;
    if ( $option{field_msg} ) {
        my %msg = %{ $option{field_msg} };
        foreach my $f ( keys %msg ) {
            next if !$lookup{$f};
            $err{ $realname{ $lookup{$f} } } = $msg{$f};
        }
    }
    my $q = $app->query;
    $app->clear_utf8_param( $display_info{tstamp} );
    foreach my $f (qw(id formto formfrom formmsg)) {
        $app->clear_utf8_param( $realname{$f} );
        $q->param( $realname{$f}, $q->param( $oldfield{$f} ) );
    }

    #make the fields
    my %type = (
        formto    => 'email',
        formfrom   => 'email',
        formmsg     => 'raw_text',
    );
    my @fields;
    
    
    my @obfuscated = qw(formfrom formmsg);
    $author ||= q{};
    unshift @obfuscated, 'formto' if $author !~ /author(\d+)/;
    foreach my $f (@obfuscated) {
        push @fields,
          ( $app->prompt_field_ref(
                id        => $realname{$f},
                prompt_as => $type{$f},
                required  => $f ne 'formmsg',
            ),
            $app->prompt_field_ref(
                id        => $fakename{$f},
                prompt_as => $type{$f},
                hidden    => 1,
            ),
          );

        #add labels after (prompt_field_ref runs them through language)
        $fields[-2]->[2]->{label} =
          $site->get_pref_value("html_emailform_$f");
        $fields[-1]->[2]->{label} = 'Leave blank';
    }
    push @fields,
      ( $app->prompt_field_ref(
            id           => 'bmf_cc',
            prompt_as    => 'boolean',
            option_label => 'EMAIL_Send me a copy',
        ),
        $app->prompt_field_ref(
            id        => $display_info{tstamp},
            value     => $display_info{local_time},
            prompt_as => 'hidden',
        ),
        $app->prompt_field_ref(
            id        => $realname{id},
            value     => $page->id,
            prompt_as => 'hidden',
        ),
      );

    my $submit = $app->prompt_field_ref(
        id        => 'bmf_submit',
        prompt_as => 'submit',
        value     => $app->language('BM_SUBMIT_LABEL_Send'),
    );
    my @fieldsets = (
        $app->prompt_fieldset_ref(
            fields    => \@fields,
            query     => $q,
            field_msg => \%err,
            post_html => $app->get_captcha_html($site),
        ),
        $app->prompt_fieldset_ref(
            fields    => [ $submit ],
        ),
    );

    my ( $title, $message ) =
      $app->title_and_message(
        title     => $option{title},
        message   => $option{message},
        field_msg => \%err,
      );
    my $form_url = $app->build_url(
            script => 'bm-email.cgi',
            rm     => 'email-page',
            site   => $site->id,
            args   => \@args,
    );
    my $self_url =
      $page->page_url( $site,
        { section => $site->section_obj_by_id($sec_id) } );
    
    my $html = $app->html_template_screen(
        'screen_public_form.tmpl',
        bmcp_title => $title,
        message    => $message,
        fieldsets  => \@fieldsets,
        form_url   => $form_url,
        self_url => $self_url,
    );
    #handle the challenge question if appropriate
    return BigMed::PageUtils::replace_all_includes( $site, $html );
}

sub return_to_page {
    my ( $app, $url ) = @_;
    $app->header_type('redirect');
    $app->header_props( -url => $url );
    return "Redirecting to $url";
}

sub _referrer_commentcgi_match {
    my $app = shift;
    return 1 if !$ENV{HTTP_REFERER};
    my $url = $app->query->url( -path_info => 1 );
    return $ENV{HTTP_REFERER} =~ m{\Q$url\E}ms ? 'cgi' : 0;
}


1;

__END__

