#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - comet_license_registration_sync
#                                      Copyright 2025 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package scripts::comet_license_registration_sync;

use strict;
use warnings;

use Whostmgr::CometBackup::Constants ();

our $PLUGIN_DIR     = '/var/cpanel/plugins/comet-backup';
our $APP_DIR        = '/var/cpanel/apps';
our $CONF_FILE      = 'whm-comet-backup.conf';
our $PLUGIN_CONF    = "$PLUGIN_DIR/$CONF_FILE";
our $REGISTERED_LOC = "$APP_DIR/$CONF_FILE";
our $FEATURE_CONF   = "$PLUGIN_DIR/comet_backup.json";
our $REGISTER_CMD   = '/usr/local/cpanel/bin/register_appconfig';
our $UNREGISTER_CMD = '/usr/local/cpanel/bin/unregister_appconfig';
our $LICENSE_FILE   = '/var/cpanel/extended_auth/storage/comet';
our $FEATURESC_DIR  = '/usr/local/cpanel/Cpanel/Config/ConfigObj/Driver';
our $FEATURESC_FILE = "$FEATURESC_DIR/comet_backup.json";

# CPANEL-58135: a disaster recovery keeps the menu entry while it runs (its
# temporary credentials) and until support moves the cPanel license (the
# transfer-pending marker finalize writes). The page decides what the server
# may do; credentials alone (a lapsed product) do not keep the entry.
our @RECOVERY_MARKERS = (
    $Whostmgr::CometBackup::Constants::LICENSE_TRANSFER_PENDING_FILE,
    $Whostmgr::CometBackup::Constants::RECOVERY_CREDENTIALS_FILE,
);

# True when $path exists. Only ENOENT is "absent"; any other stat failure dies,
# so a run that cannot tell ends without unregistering the plugin.
sub _exists {
    my ($path) = @_;
    return 1 if stat $path;
    return 0 if $!{ENOENT};
    die "Cannot stat $path: $!\n";
}

sub has_license {
    return 1 if _exists($LICENSE_FILE);

    for my $path (@RECOVERY_MARKERS) {
        return 1 if _exists($path);
    }

    require Cpanel::Server::Type;
    my @products = Cpanel::Server::Type::get_products();
    return 1 if grep { $_ eq 'comet_backup' } @products;

    # Retail channels (e.g. company id 265) are not licensed via the product
    # list — they purchase through the cPanel Store. Register the plugin so it is
    # visible and the customer can complete that purchase path. Activation stays
    # gated on a genuine license elsewhere.
    return is_retail_company();
}

# True when the license's company id is listed in the Comet Backup retail store
# map. Core's reader treats only a missing companyid file as "no company id" and
# dies on any other read error, so a read failure ends this run without
# unregistering the plugin.
sub is_retail_company {
    require Cpanel::License::CompanyID;

    my $company_id = Cpanel::License::CompanyID::get_company_id() // return 0;

    no warnings 'once';    # %RETAIL_STORE_URLS is only referenced here
    return $Whostmgr::CometBackup::Constants::RETAIL_STORE_URLS{$company_id} ? 1 : 0;
}

sub is_registered {
    return _exists($REGISTERED_LOC);
}

# Returns the exit code. Any failure to tell the state (a stat or company-id
# read error) returns 1 and changes nothing.
sub run {
    my ( $has_license, $is_registered );
    my $ok = eval {
        $has_license   = has_license();
        $is_registered = is_registered();
        1;
    };
    if ( !$ok ) {
        warn "comet_license_registration_sync: cannot determine the license state, nothing changed: $@";
        return 1;
    }

    if ( $has_license && !$is_registered ) {
        system( $REGISTER_CMD, $PLUGIN_CONF ) == 0 or return 1;
        system( "/usr/bin/cp", $FEATURE_CONF, $FEATURESC_FILE ) == 0 or return 1;
    }
    elsif ( !$has_license && $is_registered ) {
        system( $UNREGISTER_CMD, $PLUGIN_CONF ) == 0 or return 1;
        if ( !unlink $FEATURESC_FILE ) {
            if ( !$!{ENOENT} ) {
                warn "comet_license_registration_sync: cannot remove $FEATURESC_FILE: $!\n";
                return 1;
            }
        }
    }

    return 0;
}

exit run() unless caller;

1;
