#!/usr/bin/perl
#

package Apache::LiveJournal::Interface::FotoBilder;

use strict;
use Apache::Constants qw(:common REDIRECT HTTP_NOT_MODIFIED
                         HTTP_MOVED_PERMANENTLY BAD_REQUEST);

sub run_method
{
    my $cmd = shift;

    # Available functions for this interface.
    my $interface = {
        'checksession'       => \&checksession,
        'get_user_info'      => \&get_user_info,
        'makechals'          => \&makechals,
        'set_quota'          => \&set_quota,
        'user_exists'        => \&user_exists,
        'get_auth_challenge' => \&get_auth_challenge,
        'get_groups'         => \&get_groups,
    };
    return undef unless $interface->{$cmd};

    return $interface->{$cmd}->(@_);
}

sub handler
{
    my $r = shift;
    my $uri = $r->uri;
    return 404 unless $uri =~ m#^/interface/fotobilder(?:/(\w+))?$#;
    my $cmd = $1;

    return BAD_REQUEST unless $r->method eq "POST";

    $r->content_type("text/plain");
    $r->send_http_header();

    my %POST = $r->content;
    my $res = run_method($cmd, \%POST)
        or return BAD_REQUEST;

    $res->{"fotobilder-interface-version"} = 1;

    $r->print(join("", map { "$_: $res->{$_}\n" } keys %$res));

    return OK;
}

# Is there a current LJ session?
# If so, return info.
sub get_user_info
{
    my $POST = shift;
    BML::reset_cookies();
    $LJ::_XFER_REMOTE_IP = $POST->{'remote_ip'};

    # try to get a $u from the passed uid or user, falling back to the ljsession cookie
    my $u;
    if ($POST->{uid}) {
        $u = LJ::load_userid($POST->{uid});
    } elsif ($POST->{user}) {
        $u = LJ::load_user($POST->{user});
    } else {
        $u = LJ::get_remote();
    }
    return {} unless $u && $u->{'journaltype'} eq 'P';

    my %ret = (
               user            => $u->{user},
               userid          => $u->{userid},
               statusvis       => $u->{statusvis},
               can_upload      => can_upload($u),
               gallery_enabled => can_upload($u),
               diskquota       => LJ::get_cap($u, 'disk_quota') * (1 << 20), # mb -> bytes
               fb_account      => LJ::get_cap($u, 'fb_account'),
               fb_usage        => LJ::Blob::get_disk_usage($u, 'fotobilder'),
               );

    # when the set_quota rpc call is executed (below), a placholder row is inserted
    # into userblob.  it's just used for livejournal display of what we last heard
    # fotobilder disk usage was, but we need to subtract that out before we report
    # to fotobilder how much disk the user is using on livejournal's end
    $ret{diskused} = LJ::Blob::get_disk_usage($u) - $ret{fb_usage};

    return \%ret unless $POST->{fullsync};

    LJ::fill_groups_xmlrpc($u, \%ret);
    return \%ret;
}

# Forcefully push user info out to FB.
# We use this for cases where we don't want to wait for 
# sync cache timeouts, such as user suspensions.
sub push_user_info
{
    my $uid = LJ::want_userid( shift() );
    return unless $uid;

    my $ret = get_user_info({ uid => $uid });

    eval "use XMLRPC::Lite;";
    return if $@;

    return XMLRPC::Lite
        -> proxy("$LJ::FB_SITEROOT/interface/xmlrpc")
        -> call('FB.XMLRPC.update_userinfo', $ret)
        -> result;
}

# get_user_info above used to be called 'checksession', maintain
# an alias for compatibility
sub checksession { get_user_info(@_); }

sub get_groups {
    my $POST = shift;
    my $u = LJ::load_user($POST->{user});
    return {} unless $u;

    my %ret = ();
    LJ::fill_groups_xmlrpc($u, \%ret);
    return \%ret;
}

# Pregenerate a list of challenge/responses.
sub makechals
{
    my $POST = shift;
    my $count = int($POST->{'count'}) || 1;
    if ($count > 50) { $count = 50; }
    my $u = LJ::load_user($POST->{'user'});
    return {} unless $u;

    my %ret = ( count => $count );

    for (my $i=1; $i<=$count; $i++) {
        my $chal = LJ::rand_chars(40);
        my $resp = Digest::MD5::md5_hex($chal . Digest::MD5::md5_hex($u->{'password'}));
        $ret{"chal_$i"} = $chal;
        $ret{"resp_$i"} = $resp;
    }

    return \%ret;
}

# Does the user exist?
sub user_exists
{
    my $POST = shift;
    my $u = LJ::load_user($POST->{'user'});
    return {} unless $u;

    return { 
        exists => 1,
        can_upload => can_upload($u),
    };
}

# Mirror FB quota information over to LiveJournal.
# 'user' - username
# 'used' - FB disk usage in bytes
sub set_quota
{
    my $POST = shift;
    my $u = LJ::load_userid($POST->{'uid'});
    return {} unless $u && defined $POST->{'used'};

    return {} unless $u->writer;

    my $used = $POST->{'used'} * (1 << 10);  # Kb -> bytes
    my $result = $u->do('REPLACE INTO userblob SET ' .
                        'domain=?, length=?, journalid=?, blobid=0',
                        undef, LJ::get_blob_domainid('fotobilder'),
                        $used, $u->{'userid'});

    LJ::set_userprop($u, "fb_num_pubpics", $POST->{'pub_pics'});

    return {
        status => ($result ? 1 : 0),
    };
}

sub get_auth_challenge
{
    my $POST = shift;

    return {
        chal => LJ::challenge_generate($POST->{goodfor}+0),
    };
}

#########################################################################
# non-interface helper functions
#

# Does the user have upload access?
sub can_upload
{
    my $u = shift;

    return LJ::get_cap($u, 'fb_account')
        && LJ::get_cap($u, 'fb_can_upload') ? 1 : 0;
}

1;
