# cpanel - cPanel/Blogs/WordPress.pm                 Copyright 2017 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package cPanel::Blogs::WordPress;

use strict;
use warnings;

BEGIN { unshift @INC, '/usr/local/cpanel'; }

use Cpanel::SafeRun::Object ();

our $VERSION = 1.66;
my $pkg = __PACKAGE__;

our $meta_info = {
    alternative      => 'cPanel::Blogs::WordPressX',
    deprecation_link => 'https://go.cpanel.net/wordpress-legacy-deprecation',
    setphpsuexecvar  => 1,
    adminuser_pass   => 1,
    admin_email      => 1,
    installdir       => 'wordpress',
    description      => 'PHP/MySQL based Blog',                                                                  # required
    security         => 'Configuration has to be world readable. Subject to all common PHP security problems',
    version          => '4.8.3',                                                                                 # required
    security_rank    => 2,
    website          => 'http://www.wordpress.org/',
    config_files     => ['wp-config.php'],
    chmod            => {
        '0444' => ['wp-content/plugins/cpaddons-site-software.php'],
    },
    'minimum-mysql-version' => 5.0,
    mysql                   => ['wp'],
    table_prefix            => 'wp',
    install_fields_hook     => sub {
        my ( $input_hr, $error_ref, $cpo ) = @_;
        $cpo->{'input_1blog_name'} =~ s{'}{\\'}g;
        $cpo->{'input_2blog_description'} =~ s{'}{\\'}g;
    },
    install_fields => {
        '1blog_name' => {
            label => 'Blog name',
            value => 'My WordPress Website',
            attr  => '',
            type  => 'text',
        },
        '2blog_description' => {
            label => 'Blog description',
            value => 'Just another WordPress site',
            attr  => 'size="40"',
            type  => 'text',
        }
    },
};

if ( defined &Cpanel::cPAddons::proc_keys_named_after_version ) {    ## PPI USE OK
    Cpanel::cPAddons::proc_keys_named_after_version( $meta_info, __PACKAGE__ );    ## PPI USE OK
}

my $plugin = 'cpaddons-site-software.php';

sub activate_WP_site_software_plugin {
    my $run = Cpanel::SafeRun::Object->new(
        program => 'php',
        args    => [ '-r', qq{require_once('wp-load.php'); require_once('wp-admin/includes/plugin.php'); activate_plugin('$plugin', '', false, true);} ],
    );
    return !$run->error_code();
}

sub is_WP_site_software_plugin_active {
    my $run = Cpanel::SafeRun::Object->new(
        program => 'php',
        args    => [ '-r', qq{require_once('wp-load.php'); require_once('wp-admin/includes/plugin.php'); exit(is_plugin_active('$plugin')?0:1);} ],
    );
    return !$run->error_code();
}

sub setup_plugin {
    my ($obj) = @_;

    chdir $obj->{'installdir'};

    activate_WP_site_software_plugin();
    if ( !is_WP_site_software_plugin_active() ) {
        print "<br/><strong>Warning: The plugin “cPanel & WHM® Site Software” could not be activated</strong><br/>";
    }
}

#### action functions ##
sub install {
    my $cpa = shift;

    require Cpanel::Rand;
    $cpa->{'secret_key'}     = Cpanel::Rand::getranddata(64);    # 2.5 wp-config, in 2.6 this is used for 'SECURE_AUTH_KEY'
    $cpa->{'auth_key'}       = Cpanel::Rand::getranddata(64);    # 2.6 wp-config
    $cpa->{'logged_in_key'}  = Cpanel::Rand::getranddata(64);    # 2.6 wp-config
    $cpa->{'nonce_key'}      = Cpanel::Rand::getranddata(64);    # 2.7 wp-config
    $cpa->{'auth_salt'}      = Cpanel::Rand::getranddata(64);    # 3.0.1 wp-config
    $cpa->{'secret_salt'}    = Cpanel::Rand::getranddata(64);    # 3.0.1 wp-config
    $cpa->{'logged_in_salt'} = Cpanel::Rand::getranddata(64);    # 3.0.1 wp-config
    $cpa->{'nonce_salt'}     = Cpanel::Rand::getranddata(64);    # 3.0.1 wp-config

    $cpa->{'gmt_hour_offset'} = Time::Timezone::tz_local_offset() / 3600;
    $cpa->{'_default_charset_latin1'} =
        !$cpa->{'mysql_version'}
      || $cpa->{'mysql_version'} eq '4'
      || $cpa->{'mysql_version'} =~ m{^4\.0}
      || $cpa->{'mysql_version'} =~ m{^3} ? '' : 'DEFAULT CHARSET=latin1';
    $cpa->stdinstall(@_);
    $cpa->_do_phpsuexec_perms();
    setup_plugin($cpa);
}

sub upgrade {
    my $cpa = shift;

    # gmt_* is already in object, no need to reset...
    $cpa->stdupgrade(@_);

    my $ist = $cpa->{'installed'}->{ $cpa->{'workinginstall'} };
    setup_plugin($ist);
}

sub uninstall { shift->stduninstall(@_) }

#### non action functions ##
sub installform   { print shift->{installform} }
sub upgradeform   { print shift->{upgradeform} }
sub uninstallform { print shift->{uninstallform} }

# 1;

### please MySQL, make your unix time stamp functions from GMT like they should be instead of the server's local TZ:
## In the mean time include Time::Timezone in this module (w/ out POD, Perl ver, or EXPORT stuff)
# from http://search.cpan.org/src/MUIR/Time-modules-2003.1126/lib/Time/Timezone.pm)

package Time::Timezone;

use Carp;
use strict;

# Parts stolen from code by Paul Foley <paul@ascent.com>

use vars qw($VERSION);

$Time::Timezone::VERSION = 2003.0211;

sub tz2zone {
    my ( $TZ, $time, $isdst ) = @_;

    use vars qw(%tzn_cache);

    $TZ = defined( $ENV{'TZ'} ) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'GMT' ) : ''
      unless $TZ;

    # Hack to deal with 'PST8PDT' format of TZ
    # Note that this can't deal with all the esoteric forms, but it
    # does recognize the most common: [:]STDoff[DST[off][,rule]]

    if ( !defined $isdst ) {
        my $j;
        $time = time() unless $time;
        ( $j, $j, $j, $j, $j, $j, $j, $j, $isdst ) = localtime($time);
    }

    if ( defined $tzn_cache{$TZ}->[$isdst] ) {
        return $tzn_cache{$TZ}->[$isdst];
    }

    if (
        $TZ =~ /^
                    ( [^:\d+\-,] {3,} )
                    ( [+-] ?
                      \d {1,2}
                      ( : \d {1,2} ) {0,2}
                    )
                    ( [^\d+\-,] {3,} )?
                    /x
      ) {
        $TZ = $isdst ? $4 : $1;
        $tzn_cache{$TZ} = [ $1, $4 ];
    }
    else {
        $tzn_cache{$TZ} = [ $TZ, $TZ ];
    }
    return $TZ;
}

sub tz_local_offset {
    my ($time) = @_;

    $time = time() unless $time;
    my (@l) = localtime($time);
    my $isdst = $l[8] || 0;
    my $tzenv = defined( $ENV{TZ} ) ? $ENV{TZ} : "__notz";

    if ( $Timezone::tz_local{$tzenv}
        && defined( $Timezone::tz_local{$tzenv}[$isdst] ) ) {
        return $Timezone::tz_local{$tzenv}[$isdst];
    }

    $Timezone::tz_local{$tzenv}[$isdst] = &calc_off($time);

    return $Timezone::tz_local{$tzenv}[$isdst];
}

sub calc_off {
    my ($time) = @_;

    my (@l) = localtime($time);
    my (@g) = gmtime($time);

    my $off;

    $off = $l[0] - $g[0] + ( $l[1] - $g[1] ) * 60 + ( $l[2] - $g[2] ) * 3600;

    # subscript 7 is yday.

    if ( $l[7] == $g[7] ) {

        # done
    }
    elsif ( $l[7] == $g[7] + 1 ) {
        $off += 86400;
    }
    elsif ( $l[7] == $g[7] - 1 ) {
        $off -= 86400;
    }
    elsif ( $l[7] < $g[7] ) {

        # crossed over a year boundry!
        # localtime is beginning of year, gmt is end
        # therefore local is ahead
        $off += 86400;
    }
    else {
        $off -= 86400;
    }

    return $off;
}

# constants
# The rest of the file comes from Graham Barr <bodg@tiuk.ti.com>

CONFIG: {
    use vars qw(%dstZone %zoneOff %dstZoneOff %Zone);

    %dstZone = (

        #   "ndt"  =>	-2*3600-1800,	 # Newfoundland Daylight
        "adt"     => -3 * 3600,     # Atlantic Daylight
        "edt"     => -4 * 3600,     # Eastern Daylight
        "cdt"     => -5 * 3600,     # Central Daylight
        "mdt"     => -6 * 3600,     # Mountain Daylight
        "pdt"     => -7 * 3600,     # Pacific Daylight
        "ydt"     => -8 * 3600,     # Yukon Daylight
        "hdt"     => -9 * 3600,     # Hawaii Daylight
        "bst"     => +1 * 3600,     # British Summer
        "mest"    => +2 * 3600,     # Middle European Summer
        "met dst" => +2 * 3600,     # Middle European Summer
        "sst"     => +2 * 3600,     # Swedish Summer
        "fst"     => +2 * 3600,     # French Summer
        "wadt"    => +8 * 3600,     # West Australian Daylight
                                    #   "cadt" =>  +10*3600+1800,	 # Central Australian Daylight
        "eadt"    => +11 * 3600,    # Eastern Australian Daylight
        "nzdt"    => +13 * 3600,    # New Zealand Daylight
    );

    %Zone = (
        "gmt"  => 0,                   # Greenwich Mean
        "ut"   => 0,                   # Universal (Coordinated)
        "utc"  => 0,
        "wet"  => 0,                   # Western European
        "wat"  => -1 * 3600,           # West Africa
        "at"   => -2 * 3600,           # Azores
                                       # For completeness.  BST is also British Summer, and GST is also Guam Standard.
                                       #   "bst"	=>  -3*3600,	 # Brazil Standard
                                       #   "gst"	=>  -3*3600,	 # Greenland Standard
                                       #   "nft"	=>  -3*3600-1800,# Newfoundland
                                       #   "nst"	=>  -3*3600-1800,# Newfoundland Standard
        "ast"  => -4 * 3600,           # Atlantic Standard
        "est"  => -5 * 3600,           # Eastern Standard
        "cst"  => -6 * 3600,           # Central Standard
        "cest" => +2 * 3600,           # Central European Summer
        "mst"  => -7 * 3600,           # Mountain Standard
        "pst"  => -8 * 3600,           # Pacific Standard
        "yst"  => -9 * 3600,           # Yukon Standard
        "hst"  => -10 * 3600,          # Hawaii Standard
        "cat"  => -10 * 3600,          # Central Alaska
        "ahst" => -10 * 3600,          # Alaska-Hawaii Standard
        "nt"   => -11 * 3600,          # Nome
        "idlw" => -12 * 3600,          # International Date Line West
        "cet"  => +1 * 3600,           # Central European
        "met"  => +1 * 3600,           # Middle European
        "mewt" => +1 * 3600,           # Middle European Winter
        "swt"  => +1 * 3600,           # Swedish Winter
        "fwt"  => +1 * 3600,           # French Winter
        "eet"  => +2 * 3600,           # Eastern Europe, USSR Zone 1
        "bt"   => +3 * 3600,           # Baghdad, USSR Zone 2
                                       #   "it"	=>  +3*3600+1800,# Iran
        "zp4"  => +4 * 3600,           # USSR Zone 3
        "zp5"  => +5 * 3600,           # USSR Zone 4
        "ist"  => +5 * 3600 + 1800,    # Indian Standard
        "zp6"  => +6 * 3600,           # USSR Zone 5
                                       # For completeness.  NST is also Newfoundland Stanard, and SST is also Swedish Summer.
                                       #   "nst"	=>  +6*3600+1800,# North Sumatra
                                       #   "sst"	=>  +7*3600,	 # South Sumatra, USSR Zone 6
        "wast" => +7 * 3600,           # West Australian Standard
                                       #   "jt"	=>  +7*3600+1800,# Java (3pm in Cronusland!)
        "cct"  => +8 * 3600,           # China Coast, USSR Zone 7
        "jst"  => +9 * 3600,           # Japan Standard, USSR Zone 8
                                       #   "cast"	=>  +9*3600+1800,# Central Australian Standard
        "east" => +10 * 3600,          # Eastern Australian Standard
        "gst"  => +10 * 3600,          # Guam Standard, USSR Zone 9
        "nzt"  => +12 * 3600,          # New Zealand
        "nzst" => +12 * 3600,          # New Zealand Standard
        "idle" => +12 * 3600,          # International Date Line East
    );

    %zoneOff    = reverse(%Zone);
    %dstZoneOff = reverse(%dstZone);

    # Preferences

    $zoneOff{0}       = 'gmt';
    $dstZoneOff{3600} = 'bst';

}

sub tz_offset {
    my ( $zone, $time ) = @_;

    return &tz_local_offset() unless ($zone);

    $time = time() unless $time;
    my (@l) = localtime($time);
    my $dst = $l[8];

    $zone = lc $zone;

    if ( $zone =~ /^([\-\+]\d{3,4})$/ ) {
        my $sign = $1 < 0 ? -1 : 1;
        my $v = abs( 0 + $1 );
        return $sign * 60 * ( int( $v / 100 ) * 60 + ( $v % 100 ) );
    }
    elsif ( exists $dstZone{$zone} && ( $dst || !exists $Zone{$zone} ) ) {
        return $dstZone{$zone};
    }
    elsif ( exists $Zone{$zone} ) {
        return $Zone{$zone};
    }
    undef;
}

sub tz_name {
    my ( $off, $time ) = @_;

    $time = time() unless $time;
    my (@l) = localtime($time);
    my $dst = $l[8];

    if ( exists $dstZoneOff{$off} && ( $dst || !exists $zoneOff{$off} ) ) {
        return $dstZoneOff{$off};
    }
    elsif ( exists $zoneOff{$off} ) {
        return $zoneOff{$off};
    }
    sprintf( "%+05d", int( $off / 60 ) * 100 + $off % 60 );
}

1;
