#/*
# *  Copyright 2007-2008 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: Cap.pm 1812 2009-01-10 16:29:47Z hikarin $
#

package Img0ch::Cap;

use strict;
use Digest::MD5 qw();

BEGIN {
    my $pkg        = __PACKAGE__;
    my @privileges = qw(
        can_post_without_limit
        can_pass_proxy_access
        can_create_thread_limitless
        can_post_sambaless
        can_throttled_post
        can_double_post
        can_create_thread_to_readonly
        can_post_to_readonly
        can_id_to_unknown
        can_add_cap_name
    );

    for my $privilege (@privileges) {
        my $attr = '__' . $privilege;
        no strict 'refs';
        *{"${pkg}::${privilege}"} = sub { $_[0]->{$attr} || 0 }
    }
    no strict 'refs';
    *{"${pkg}::privilege_methods"} = sub { return \@privileges }
}

sub new {
    my ( $iClass, $iBBS, $pass ) = @_;
    my $iKernel = $iBBS->get_kernel();
    my $repos   = $iKernel->get_repos_path('cap');

    if ( $iKernel->get_config()->get('compatible.cap') ) {

        # for preventing deep recursion
        if ( caller(1) ne 'Img0ch::Compat::Cap' ) {
            require Img0ch::Compat::Cap;
            Img0ch::Compat::Cap::update($iBBS);
        }
    }

    bless {
        _bbs      => $iBBS->get_id(),
        _encoding => $iBBS->get_encoding(),
        _kernel   => $iKernel,
        __name    => '',
        __b64     => Digest::MD5::md5_base64($pass),
        __hex     => Digest::MD5::md5_hex($pass),
        _repos    => $iKernel->get_repos($repos),
        __utf8    => $iBBS->is_utf8(),
    }, $iClass;
}

sub load { $_[0]->{_repos}->load(); return 1 }

sub is_valid {
    my ($iCap) = @_;
    my $iRepos = $iCap->{_repos};
    my $bbs    = $iCap->{_bbs};
    my $b64    = $iCap->{__b64};
    my $hex    = $iCap->{__hex};

    my $gid = $iRepos->get_int("I:C:I.${hex}.gid")
        || $iRepos->get_int("I:C:I.${b64}.gid");
    $gid or return 0;
    $iRepos->get("I:C:G:S.${gid}.${bbs}")
        || $iRepos->get("I:C:G:S.${gid}.0")
        || return 0;
    my $priv = $iRepos->get_int("I:C:G.${gid}.privilege");

    my $iKernel = $iCap->{_kernel};
    my $charset = $iCap->{_encoding};
    my $utf8    = $iRepos->get("I:C:I.${hex}.utf8");

    # >= 2.1.27 and board uses Shift_JIS
    if ( !$iCap->{__utf8} and $utf8 ) {
        $iCap->{__name} = $iKernel->get_encoded_str(
            $iRepos->get("I:C:I.${hex}.name")
                || $iRepos->get("I:C:I.${b64}.name"),
            $charset, 'utf8'
        );
    }

    # < 2.1.27
    # UTF-8 encoded boards also use (share) Shift_JIS encoded cap names.
    elsif ( !$utf8 ) {
        $iCap->{__name} = $iKernel->get_encoded_str(
            $iRepos->get("I:C:I.${hex}.name")
                || $iRepos->get("I:C:I.${b64}.name"),
            $charset, 'sjis'
        );
    }

    # >= 2.1.27 and board uses UTF-8
    else {
        $iCap->{__name} = $iRepos->get("I:C:I.${hex}.name")
            || $iRepos->get("I:C:I.${b64}.name");
    }

    $iCap->{__can_post_without_limit}        = $priv & 1   ? 1 : 0;
    $iCap->{__can_pass_proxy_access}         = $priv & 2   ? 1 : 0;
    $iCap->{__can_create_thread_limitless}   = $priv & 4   ? 1 : 0;
    $iCap->{__can_post_sambaless}            = $priv & 8   ? 1 : 0;
    $iCap->{__can_throttled_post}            = $priv & 16  ? 1 : 0;
    $iCap->{__can_double_post}               = $priv & 32  ? 1 : 0;
    $iCap->{__can_create_thread_to_readonly} = $priv & 64  ? 1 : 0;
    $iCap->{__can_post_to_readonly}          = $priv & 128 ? 1 : 0;
    $iCap->{__can_id_to_unknown}             = $priv & 256 ? 1 : 0;
    $iCap->{__can_add_cap_name}              = $priv & 512 ? 1 : 0;
    return 1;
}

sub get_name { $_[0]->{__name} || '' }

sub get_pass_md5 { $_[0]->{__pass} }

1;
__END__

=head1 NAME

Img0ch::Cap - キャップを管理するクラス

=head1 SYNOPSYS

  use Img0ch::Cap;

  my $iCap = Img0ch::Cap->new($iBBS, 'foobar');
  if ( $iCap->is_valid() ) {
      my $name = $iCap->get_name();
      my $pass_md5_base64 = $iCap->get_pass_md5();
      if ( $iCap->can_post_without_limit() ) {
          # process something...
      }
  }

=head2 new

=over 4

=item Arguments

$iBBS (Img0ch::BBS), $cap_pass

=item Return Value

$iCap (Img0ch::Cap itself)

=back

I<Img0ch::Cap>のオブジェクトを作成します。

=head2 load

=over 4

=item Arguments

none

=item Return Value

1

=back

キャップ情報を読み込みます。

=head2 is_valid

=over 4

=item Arguments

none

=item Return Value

1(valid) or 0

=back

コンストラクタで渡されたパスのキャップが存在するかを調べます。
一致した場合は権限を設定し、1を返します。
一致しなかった場合は0を返します。

=head2 get_name

=over 4

=item Arguments

none

=item Return Value

$name or ""(null-string)

=back

オブジェクトに保存されたキャップ情報のうちの名前を返します。

=head2 get_pass_md5

=over 4

=item Arguments

none

=item Return Value

$pass_md5_base64

=back

オブジェクトに保存されたキャップ情報のうちパスワードをMD5で計算し、
BASE64でエンコードされた文字列を返します。

=head2 can_post_without_limit

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報に長さまたは量的な制限が解除された権限があるかを返します。

=head2 can_pass_proxy_access

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報にプロクシまたは書き込み規制中でも書き込むことが出来る権限があるかを返します。

=head2 can_create_thread_limitless

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報にスレッド作成制限が解除された権限があるかを返します。

=head2 can_throttled_post

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報に連続投稿制限が解除された権限があるかを返します。

=head2 can_double_post

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報に二重投稿が解除された権限があるかを返します。

=head2 can_create_thread_to_readonly

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報に読み込み制限がかかっている掲示板でもスレッドが作成できる権限があるかを返します。
(ただし完全に読み込み専用の掲示板には適用できません)

=head2 can_post_to_readonly

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報に読み込み制限がかかっている掲示板でも投稿できる権限があるかを返します。
(ただし完全に読み込み専用の掲示板には適用できません)

=head2 can_id_to_unknown

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報にIDを隠匿できる権限があるかを返します。
(掲示板設定のID表示がホスト、強制、任意表示に適用されます。表示しない場合は無効です)

=head2 can_add_cap_name

=over 4

=item Arguments

none

=item Return Value

1(has privilege) or none

=back

オブジェクトに保存されたキャップ情報にキャップ名を付加出来る権限があるかを返します。

=head1 AUTHOR

hkrn E<lt>hikarin@users.sourceforge.jpE<gt>

=cut
