#/*
# *  Copyright 2007-2009 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 1873 2009-12-01 17:53:43Z 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 $digest  = $hash->{digest};
    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 $samba_count = 0;
    my $last_digest = '';
    my $samba_wait  = $hash->{samba_wait};

    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 );
    }

    my $my_atime     = 0;
    my $should_reset = 0;
    for my $datum (@data) {
        my $rec = [ split "\t", $datum ];
        ( $atime, $last_digest, $is_samba, undef ) = @$rec;
        if ( $rec->[3] eq $term ) {

     # SAMBA24 の発動条件
     # * 最低二回以上は書き込みをしている
     # * SambaWait (秒) 内にアクセスしている
     # * 投稿間隔が SambaCount (秒) 内にある
     # ただし例外規則がある
     # * 投稿間隔が SambaCount (秒) 以上であればリセットする
            if ($my_atime) {
                my $wait = $atime - $my_atime;
                if ( $samba_close <= $wait ) {
                    $samba_count = 0;
                }
                elsif ( $samba_wait > $now - $atime and $samba_close > $wait )
                {
                    $samba_count++;
                }
            }
            $my_atime = $atime;
            push @{$my_stack}, $datum;
        }
        else {
            push @{$other_stack}, $datum;
        }
    }

# 「現在の書き込み時刻」が最後の書き込み時刻との差分で
# SambaCount (秒) 以上であればリセットする
    $now - $my_atime >= $samba_close and $samba_count = 0;

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

    if ( !$hash->{samba_ok} ) {
        if ($is_samba) {

# 現在の書き込み時刻が最後の書き込み時刻との差分であれば
# SambaWait (秒) であれば規制を解除する
            if ( $now >= $atime + $samba_wait ) {
                _flush( $iRepos, \@data, $bbs );
                return 1;
            }

            # そうでなければ残りの分数を表示する
            else {
                $hash->{samba_rest}
                    = int( ( $atime - ( $now - $samba_wait ) ) / 60 ) || 1;
                $hash->{error} = 'DENY_FROM_SAMBA_LISTED_HOST';
                return 0;
            }
        }
    }
    if ( !$hash->{duplicate_ok} ) {
        if ( $last_digest eq $digest ) {
            $hash->{error} = 'DOUPLICATED_POST';
            return 0;
        }
    }

    if ( !$hash->{throttle_ok} ) {
        my $throttle = $my_count > $timecount ? $timecount : $my_count;

# 書き込みログのうち自分の投稿数が timecount 以上であれば連続投稿規制をかける
        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 - $my_atime;
            my $mark = 0;

            # 秒数を表示する
            if ( $samba_count < 4 ) {
                $hash->{error} = 'SAMBA_LEVEL1';
            }

            # そろそろ書き込みが禁止されるよ
            elsif ( $samba_count == 4 ) {
                $hash->{error} = 'SAMBA_LEVEL2';
            }

            # 書き込みが禁止されました
            # よって SAMBA 中フラグを立てる
            else {
                $mark = 1;
                $hash->{error} = 'SAMBA_LEVEL3';
            }
            _write( $iRepos, \@data, $bbs, [ $now, $digest, $mark, $term ] );
            return 0;
        }
    }

    _write( $iRepos, \@data, $bbs, [ $now, $digest, 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__
