#/*
# *  Copyright 2007 hkrn <hikarin@users.sourceforge.jp>
# *
# *  Licensed under the Apache License, Version 2.0 (the "License");
# *  you may not use this file except in compliance with the License.
# *  You may obtain a copy of the License at
# *
# *      http://www.apache.org/licenses/LICENSE-2.0
# *
# *  Unless required by applicable law or agreed to in writing, software
# *  distributed under the License is distributed on an "AS IS" BASIS,
# *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# *  See the License for the specific language governing permissions and
# *  limitations under the License.
# */
#
# $Id: Res.pm 1613 2007-11-23 12:49:53Z hikarin $
#

package Img0ch::Filter::Res;

use strict;

sub write_ok {
    my ( $iClass, $hash, $iObject ) = @_;
    my $is_bbs = ( ref $iObject || '' ) eq 'Img0ch::BBS' ? 1 : 0;
    my $iKernel = $is_bbs ? $iObject->get_kernel() : $iObject;
    my $now     = $hash->{stamp};
    my $len     = $hash->{len};
    my $ip      = $hash->{ip};
    my $ser     = $hash->{serial};
    my $term
        = $ser
        ? $hash->{serial}
        : join( '.', unpack( 'C*', $hash->{ip} ) );

    my $iRepos = $iKernel->get_repos( $iKernel->get_repos_path('restrict') );
    my $bbs = $is_bbs ? $iObject->get_name() : 'test';
    my $samba_close = $hash->{samba_close} || 0;
    my $my_stack    = [];
    my $other_stack = [];
    my $atime       = 0;
    my $is_samba    = 0;
    my $latest_len  = 0;
    my $samba_count = 0;

    my @data      = split "\n", $iRepos->get_binary("I:F:R.${bbs}");
    my $datacount = scalar @data;
    my $timecount = $hash->{timecount};
    if ( $datacount > $timecount ) {
        @data = splice @data, ( $timecount * -1 );
    }

    for my $datum (@data) {
        my $rec = [ split "\t", $datum ];
        ( $atime, $latest_len, $is_samba, undef ) = @$rec;
        if ( $rec->[3] eq $term ) {
            $samba_close >= $now - $atime and $samba_count++;
            push @{$my_stack}, $datum;
        }
        else {
            push @{$other_stack}, $datum;
        }
    }

    my $my_count  = scalar @{$my_stack};
    my $can_store = $hash->{store};
    if ( $can_store > 0 and $my_count == 0 ) {
        _write( $iRepos, \@data, $bbs, [ $now, $len, 0, $term ] );
        return 1;
    }

    if ( !$hash->{samba_ok} ) {
        if ($is_samba) {
            my $wait = $hash->{samba_wait};
            if ( $now >= $atime + $wait ) {
                _flush( $iRepos, \@data, $bbs );
                return 1;
            }
            else {
                $hash->{samba_rest}
                    = int( ( $atime - ( $now - $wait ) ) / 60 ) || 1;
                $hash->{error} = 'DENY_FROM_SAMBA_LISTED_HOST';
                return 0;
            }
        }
    }

    if ( !$hash->{duplicate_ok} ) {
        if ( $latest_len == $len ) {
            $hash->{error} = 'DOUPLICATED_POST';
            return 0;
        }
    }

    if ( !$hash->{throttle_ok} ) {
        my $throttle = $my_count > $timecount ? $timecount : $my_count;
        if ( $throttle >= $hash->{timeclose} ) {
            $hash->{error} = 'THROTTLED_POST';
            return 0;
        }
    }

    if ( !$hash->{samba_ok} ) {
        if ( $samba_count > 0 ) {
            $hash->{samba_count} = $samba_count;
            $hash->{samba_rest}  = $now - $atime;
            my $mark = 0;
            if ( $samba_count < 4 ) {
                $hash->{error} = 'SAMBA_LEVEL1';
            }
            elsif ( $samba_count == 4 ) {
                $hash->{error} = 'SAMBA_LEVEL2';
            }
            else {
                $mark = 1;
                $hash->{error} = 'SAMBA_LEVEL3';
            }
            _write( $iRepos, \@data, $bbs, [ $now, $len, $mark, $term ] );
            return 0;
        }
    }

    _write( $iRepos, \@data, $bbs, [ $now, $len, 0, $term ] );
    return 1;
}

sub _write {
    my ( $iRepos, $data, $bbs, $my_rec ) = @_;
    push @$data, join( "\t", @$my_rec );
    $iRepos->set_binary( "I:F:R.${bbs}", join( "\n", @$data ) );
    $iRepos->save();
    return;
}

sub _flush {
    my ( $iRepos, $data, $bbs ) = @_;
    $iRepos->set_binary( "I:F:R.${bbs}", join( "\n", @$data ) );
    $iRepos->save();
    return;
}

1;
__END__
