<?php
if (!defined('ABSPATH')) exit;
// @codingStandardsIgnoreStart
/*
Obtain and manage extra features for UpdraftPlus Backup

This plugin communicates with the mothership via encrypted HTTPS and falls back to HTTP if this fails; even over HTTP, nothing of significant value is thereby put at risk - see https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/
However, if your organisation has strong requirements for use of SSL, then add the following line to your wp-config.php to forbid any non-https communications:

define('UPDRAFTPLUS_ADDONS_SSL', true);

This plugin:
- over-rides the update mechanism for the UpdraftPlus plugin, so that we can get them from our site
- shows the user his installed and available add-ons
- also over-rides its own update mechanism

This directory should not be added to the wordpress.org SVN
*/
// @codingStandardsIgnoreEnd
// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_fclose, WordPress.WP.AlternativeFunctions.file_system_operations_fopen, WordPress.WP.AlternativeFunctions.file_system_operations_fwrite, WordPress.WP.AlternativeFunctions.file_system_operations_fgets, WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents, WordPress.WP.AlternativeFunctions.file_system_operations_mkdir, WordPress.WP.AlternativeFunctions.file_system_operations_fread, WordPress.WP.AlternativeFunctions.file_system_operations_chmod, WordPress.WP.AlternativeFunctions.file_system_operations_fputs, WordPress.WP.AlternativeFunctions.file_system_operations_is_writeable, WordPress.WP.AlternativeFunctions.file_system_operations_chown, WordPress.WP.AlternativeFunctions.file_system_operations_chgrp, WordPress.WP.AlternativeFunctions.file_system_operations_touch -- Native PHP fileystem function is used for direct control and performance because it can bypass additional layers of abstraction so that no overhead from the WordPress filesystem API's internal handling
define('UDADDONS2_DIR', dirname(realpath(__FILE__)));
define('UDADDONS2_URL', UPDRAFTPLUS_URL.'/udaddons');
define('UDADDONS2_SLUG', 'updraftplus-addons');
define('UDADDONS2_PAGESLUG', 'updraftplus');

$udaddons2_mothership = (defined('UPDRAFTPLUS_ADDONS_SSL') && !UPDRAFTPLUS_ADDONS_SSL) ? 'http://' : 'https://';

$udaddons2_mothership .= defined('UDADDONS2_TEST_MOTHERSHIP') ? UDADDONS2_TEST_MOTHERSHIP : 'updraftplus.com';

global $updraftplus_addons2; // Need to explicitly globalise the variable or WP-CLI won't recognise it https://github.com/wp-cli/wp-cli/issues/4019#issuecomment-297410839

$updraftplus_addons2 = new UpdraftPlusAddons2('updraftplus', $udaddons2_mothership);

class UpdraftPlusAddons2 {

	public $slug;

	public $url;

	public $debug = false;

	public $user_addons;

	public $user_support;

	public $available_addons;

	public $remote_addons;

	public $plug_updatechecker;

	private $admin_notices = array();

	private $saved_site_id;
	
	private $plugin_file;

	/**
	 * Not used anywhere, but it is set.
	 *
	 * @var UpdraftPlusAddOns_Options2
	 */
	private $options;

	/**
	 * Constructor
	 *
	 * @param String $slug - the plugin's slug
	 * @param String $url  - the URL of the mothership that updates are checked at
	 */
	public function __construct($slug, $url) {
		$this->slug = $slug;
		$this->url = $url;

		// Hide unwanted/user-hostile JetPack promotions, which cause genuine directory search results to be de-prioritised by default (if you use any of JetPack's 45 modules, then it promotes things from the others to the top of search results): https://wptavern.com/jetpack-7-1-adds-feature-suggestions-to-plugin-search-results. If using one JetPack module really does mean that you now automatically prefer all the others, then remove these lines, or add higher-priority filters to add them back.
		add_filter('jetpack_show_promotions', '__return_false', 20);
		add_filter('jetpack_just_in_time_msgs', '__return_false', 20);
		
		// This needs to exact match PluginUpdateChecker's view
		$this->plugin_file = plugin_basename($this->slug.'/'.$this->slug.'.php');

		add_action('updraftplus_restore_db_pre', array($this, 'updraftplus_restore_db_pre'));
		add_action('updraftplus_restored_db_is_migration', array($this, 'updraftplus_restored_db_is_migration'));

		add_action('updraftplus_showrawinfo', array($this, 'updraftplus_showrawinfo'));

		add_action((is_multisite() && class_exists('UpdraftPlusAddOn_MultiSite')) ? 'network_admin_menu' : 'admin_menu', array($this, 'admin_menu'));

		add_action('wp_ajax_udaddons_claimaddon', array($this, 'ajax_udaddons_claimaddon'));
		add_action('wp_ajax_udmupdater_ajax', array($this, 'ajax_login_and_claim_addons'));

		if (class_exists('UpdraftPlusAddons')) return;

		// Prevent updates from wordpress.org showing in all circumstances. Run with lower than default priority, to allow later processes to add something.
		add_filter('site_transient_update_plugins', array($this, 'site_transient_update_plugins'), 9);

		// Over-ride update mechanism for the plugin
		if (is_readable(UPDRAFTPLUS_DIR.'/vendor/yahnis-elsts/plugin-update-checker/plugin-update-checker.php')) {

			updraft_try_include_file('vendor/yahnis-elsts/plugin-update-checker/plugin-update-checker.php', 'include_once');

			add_filter('puc_check_now-'.$this->slug, array($this, 'puc_check_now'), 10, 3);
			add_filter('puc_retain_fields-'.$this->slug, array($this, 'puc_retain_fields'));
			add_filter('puc_request_info_options-'.$this->slug, array($this, 'puc_request_info_options'));
			// Run after the PluginUpdateChecker has done its stuff
			add_filter('site_transient_update_plugins', array($this, 'possibly_inject_translations'), 11);
			// If https does not work, then try http

			$plug_updatechecker = Puc_v4_Factory::buildUpdateChecker($this->url."/plugin-info/", WP_PLUGIN_DIR.'/'.$this->slug.'/'.$this->slug.'.php', $this->slug, 24);
			
			// The null case is seen in HS#36382
			if (null === $plug_updatechecker) {
				error_log("UpdraftPlus: Puc_v4_Factory::buildUpdateChecker() return a null object");
			} else {
				$plug_updatechecker->addQueryArgFilter(array($this, 'updater_queryargs_plugin'));
				if ($this->debug) $plug_updatechecker->debugMode = true;
				
				$plug_updatechecker->addFilter('request_metadata_http_result', array($this, 'request_metadata_http_result'), 10, 3);
				
				$this->plug_updatechecker = $plug_updatechecker;
			}

			$this->move_updraftplus_update_cron();
		}
	}

	/**
	 * This function is used to redistribute update check times; it is a control to help spread server load
	 *
	 * @return void
	 */
	private function move_updraftplus_update_cron() {

		$cron_move_date = 1607558400; // 2020-12-10 00:00
		$cleanup_date = 1607644800; // 2020-12-11 00:00
		$option_name = 'updraftplus_move_update_cron_dec20';
		
		$time_now = time();
		$start_of_today = $time_now - ($time_now % 86400);

		if ($start_of_today > $cleanup_date + 172800) return;
	
		$moved_cron = get_site_option($option_name);

		if ($cron_move_date == $start_of_today && !$moved_cron) {
			$timestamp = wp_next_scheduled('puc_cron_check_updates-updraftplus');
			$begintime1 = $cron_move_date + 3600 * 9; // 09:00
			$endtime1 = $begintime1 + 3600 * 12;
			// $begintime2 = 1588953600; // 2020-05-08 16:00
			// $endtime2 = $begintime2 + 7 * 3600;

			if ($timestamp >= $begintime1 && $timestamp <= $endtime1) {
				wp_clear_scheduled_hook('puc_cron_check_updates-updraftplus');
				wp_schedule_event($timestamp + 13 * 3600, 'daily', 'puc_cron_check_updates-updraftplus');
				$this->update_option($option_name, true);
			}
			
		} elseif ($moved_cron && $start_of_today >= $cleanup_date) {
			delete_site_option($option_name);
		}
	}

	/**
	 * WordPress filter, from plugins-updates-checker. We use it to fall back to http:// if https:// fails
	 *
	 * @param Mixed	 $result  The result of the first HTTP request
	 * @param String $url	  The URL being fetched
	 * @param Array	 $options The options for the WP HTTP API
	 *
	 * @return Mixed - the result of the WP HTTP API call to use
	 */
	public function request_metadata_http_result($result, $url, $options) {
	
		$url_non_ssl = preg_replace('/^https:/i', 'http:', $url);
	
		if (is_wp_error($result) && $url != $url_non_ssl && (!defined('UPDRAFTPLUS_ADDONS_SSL') || !UPDRAFTPLUS_ADDONS_SSL)) {
		
			$result = wp_remote_get(
				$url_non_ssl,
				$options
			);
		
		}
		
		return $result;
	
	}
	
	/**
	 * Inject our translation information into the updates object. Runs upon the WP filter site_transient_update_plugins .
	 *
	 * @param Object $updates
	 *
	 * @return Object
	 */
	public function possibly_inject_translations($updates) {
	
		$slug = $this->slug;
	
		$checker = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;

		if (!isset($checker->update->translations) || !is_array($checker->update->translations)) return $updates;
		
		foreach ($checker->update->translations as $translation) {

			// Remove any existing updates indicated for this slug/language - i.e. we want it over-ridden with the result from the server
			if (isset($updates->translations) && is_array($updates->translations)) {
				foreach ($updates->translations as $k => $translation) {
					if ('plugin' == $translation['type'] && $translation['slug'] == $slug) unset($updates->translations[$k]);
				}
				
			} else {
				$updates->translations = array();
			}
			
			// Add our translation onto the array
			$translation_array = (array) $translation;
			$translation_array['type'] = 'plugin';
			$translation_array['slug'] = $slug;
			
			$updates->translations[] = $translation_array;
			
		}
		
		return $updates;
	}
	
	public function puc_request_info_options($opts) {
		if (is_array($opts)) $opts['timeout'] = 10;
		return $opts;
	}

	/**
	 * Print out update URL information
	 */
	public function updraftplus_showrawinfo() {
		echo "<p>Updates URL: ".esc_url($this->url)."</p>";
	}

	public function updraftplus_restore_db_pre() {
		$this->saved_site_id = $this->siteid();
	}

	public function updraftplus_restored_db_is_migration() {
		$option = UDADDONS2_SLUG.'_siteid';
		if (!empty($this->saved_site_id)) {
			global $updraftplus;
			$updraftplus->log("Restored pre-migration site ID for this installation");
			delete_site_option($option);
			add_site_option($option, $this->saved_site_id);
		}
	}

	/**
	 * Fields to be retained from the remote request
	 *
	 * @param Array $fields - list of fields
	 *
	 * @return Array - list after filtering
	 */
	public function puc_retain_fields($fields) {
		$retain_these = array('translations', 'extraProperties');
		foreach ($retain_these as $retain) {
			if (!in_array($retain, $fields)) $fields[] = $retain;
		}
		return $fields;
	}

	public function admin_notices() {
		foreach ($this->admin_notices as $key => $notice) {
			$notice = '<span style="font-size: 115%;">'.$notice.'</span>';
			if (is_numeric($key)) {
				$this->show_admin_warning($notice);
			} else {
				$this->show_admin_warning($notice, 'error updraftupdatesnotice updraftupdatesnotice-'.$key);
			}
		}
	}

	/**
	 * Runs upon the WP action admin_menu or network_admin_menu
	 */
	public function admin_menu() {
		global $pagenow, $updraftplus;

		// Do we want to display a notice about the upcoming or past expiry of their UpdraftPlus subscription?
		if (!empty($this->plug_updatechecker) && !empty($this->plug_updatechecker->optionName) && current_user_can('update_plugins')) {
			// (!is_multisite() && 'options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow) ||
			if ('plugins.php' == $pagenow || 'update-core.php' == $pagenow || (('options-general.php' == $pagenow || 'admin.php' == $pagenow) && !empty($_REQUEST['page']) && 'updraftplus' == $_REQUEST['page'])) {
				$do_expiry_check = true;
				$dismiss = '';
			} elseif (is_admin()) {
				$dismissed_until = UpdraftPlus_Options::get_updraft_option('updraftplus_dismissedexpiry', 0);
				if ($dismissed_until <= time()) {
					$do_expiry_check = true;
					$dismiss = '<div style="float:right; position: relative; top:-24px;" class="ud-expiry-dismiss"><a href="#" onclick="jQuery(\'.ud-expiry-dismiss\').parent().slideUp(); jQuery.post(ajaxurl, {action: \'updraft_ajax\', subaction: \'dismissexpiry\', nonce: \''.wp_create_nonce('updraftplus-credentialtest-nonce').'\' })">'.sprintf(__('Dismiss from main dashboard (for %s weeks)', 'updraftplus'), 2).'</a></div>';
				}
			}
		}

		$oval = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;
		$updateskey = 'x-spm-expiry';
		$supportkey = 'x-spm-support-expiry';
		$metakey = 'x-spm-meta';
		$subscription_activekey = 'x-spm-subscription-active';
		
		$meta_info = (is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$metakey])) ? (array) json_decode($oval->update->extraProperties[$metakey], true) : array();

		$yourversionkey = 'x-spm-yourversion-tested';

		if (is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$yourversionkey]) && UpdraftPlus_Options::user_can_manage() && (!defined('UPDRAFTPLUS_DISABLECOMPATNOTICE') || true != UPDRAFTPLUS_DISABLECOMPATNOTICE)) {

			// Prevent false-positives
			if (file_exists(UPDRAFTPLUS_DIR.'/readme.txt') && $fp = fopen(UPDRAFTPLUS_DIR.'/readme.txt', 'r')) {
				$file_data = fread($fp, 1024);
				if (preg_match("/Tested up to: (\d+(\.\d+)+)/", $file_data, $matches)) {
					$readme_says = $matches[1];
				}
				fclose($fp);
			}

			$wp_version = $updraftplus->get_wordpress_version();
			$compare_wp_version = (preg_match('/^(\d+\.\d+)\..*$/', $wp_version, $wmatches)) ? $wmatches[1] : $wp_version;
			$compare_tested_version = $oval->update->extraProperties[$yourversionkey];
			if (!empty($readme_says) && version_compare($readme_says, $compare_tested_version, '>')) $compare_tested_version = $readme_says;
			if (version_compare($compare_wp_version, $compare_tested_version, '>')) {
				$this->admin_notices['yourversiontested'] = '<strong>'.__('Warning', 'updraftplus').':</strong> '.sprintf(__('The installed version of UpdraftPlus Backup/Restore has not been tested on your version of WordPress (%s).', 'updraftplus'), $wp_version).' '.sprintf(__('It has been tested up to version %s.', 'updraftplus'), $compare_tested_version).' <a href="https://teamupdraft.com/documentation/updraftplus/topics/general/troubleshooting/seeing-warning-versions-wordpress-updraftplus-tested/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=unknown&utm_creative_format=unknown">'.__('You should update UpdraftPlus to make sure that you have a version that has been tested for compatibility.', 'updraftplus').'</a>';
			}
		}

		if (!empty($do_expiry_check) && is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$updateskey])) {
			if (preg_match('/(^|)expired_?(\d+)?(,|$)/', $oval->update->extraProperties[$updateskey], $matches)) {
				if (empty($matches[2])) {
					$message = __('Your paid access to UpdraftPlus updates for this site has expired.', 'updraftplus').' '.__('You will no longer receive updates to UpdraftPlus.', 'updraftplus').' <a href="https://teamupdraft.com/documentation/account-management/orders-and-subscriptions/why-should-i-renew-my-updraftplus-wp-optimize-or-aios-licence-and-how-do-i-do-that/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=to-regain-access&utm_creative_format=notice">'.__('To regain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>';
					if ($updraftplus->have_addons > 14 && !empty($meta_info['indirect'])) {
						$message .= ' <br>'.sprintf(__('If you have already renewed, then you need to allocate a licence to this site - %s', 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page().'?page=updraftplus&tab=addons">'.__('go here', 'updraftplus').'</a>');
					}
					$this->admin_notices['updatesexpired'] = $message.$dismiss;
				} else {
					$this->admin_notices['updatesexpired'] = sprintf(__('Your paid access to UpdraftPlus updates for %s add-ons on this site has expired.', 'updraftplus'), $matches[2]).' <a href="https://teamupdraft.com/documentation/account-management/orders-and-subscriptions/why-should-i-renew-my-updraftplus-wp-optimize-or-aios-licence-and-how-do-i-do-that/?utm_source=udp-plugin&utm_medium=referral&utm_campaign=paac&utm_content=to-regain-access&utm_creative_format=notice">'.__('To regain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>'.$dismiss;
				}
			}
			$subscription_status = apply_filters('udmupdater_subscription_active', isset($oval->update->extraProperties[$subscription_activekey]) ? $oval->update->extraProperties[$subscription_activekey] : false);
			if (empty($subscription_status)) {
				if (preg_match('/(^|,)soonpartial_(\d+)_(\d+)($|,)/', $oval->update->extraProperties[$updateskey], $matches)) {
					/* translators: 1: Number of add-ons whose updates are expiring soon, 2: Total number of add-ons on this site */
					$this->admin_notices['updatesexpiringsoon'] = sprintf(__('Your paid access to UpdraftPlus updates for %1$s of the %2$s add-ons on this site will soon expire.', 'updraftplus'), $matches[2], $matches[3]);
					$this->admin_notices['updatesexpiringsoon'] .= ' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To retain your access, and maintain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>'.$dismiss;
				} elseif (preg_match('/(^|,)soon($|,)/', $oval->update->extraProperties[$updateskey])) {
					$message = __('Your paid access to UpdraftPlus updates for this site will soon expire.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To retain your access, and maintain access to updates (including future features and compatibility with future WordPress releases) and support, please renew.', 'updraftplus').'</a>';
					if ($updraftplus->have_addons > 14 && !empty($meta_info['indirect'])) {
						$message .= ' <br>'.sprintf(__('If you have already renewed, then you need to allocate a licence to this site - %s', 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page().'?page=updraftplus&tab=addons">'.__('go here', 'updraftplus').'</a>');
					}
					$this->admin_notices['updatesexpiringsoon'] = $message.$dismiss;
				}
			}
		} elseif (!empty($do_expiry_check) && is_object($oval) && !empty($oval->update) && is_object($oval->update) && !empty($oval->update->extraProperties[$supportkey])) {
			if ('expired' == $oval->update->extraProperties[$supportkey]) {
				$this->admin_notices['supportexpired'] = __('Your paid access to UpdraftPlus support has expired.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To regain your access, please renew.', 'updraftplus').'</a>'.$dismiss;
			} elseif ('soon' == $oval->update->extraProperties[$supportkey]) {
				$this->admin_notices['supportsoonexpiring'] = __('Your paid access to UpdraftPlus support will soon expire.', 'updraftplus').' <a href="https://updraftplus.com/renewing-updraftplus-purchase/">'.__('To maintain your access to support, please renew.', 'updraftplus').'</a>'.$dismiss;
			}
		}
		add_action('all_admin_notices', array($this, 'admin_notices'));

		if (!function_exists('is_plugin_active')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
		if (is_plugin_active('updraftplus-addons/updraftplus-addons.php')) {
			deactivate_plugins('updraftplus-addons/updraftplus-addons.php');
			if (('options-general.php' == $pagenow || 'settings.php' == $pagenow) && !empty($_REQUEST['page']) && 'updraftplus-addons' == $_REQUEST['page']) {
				wp_redirect($this->addons_admin_url());
				exit;
			}
			// Do nothing more this time to avoid duplication
			return;
		} elseif (is_dir(WP_PLUGIN_DIR.'/updraftplus-addons') && current_user_can('delete_plugins')) {
			// Exists, but not active - nag them
			if ((!is_multisite() && 'options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow) || 'plugins.php' == $pagenow) add_action('all_admin_notices', array($this, 'deinstall_udaddons'));
		}

		if (class_exists('UpdraftPlusAddons')) return;

		// Refresh, if specifically requested
		if ((('options-general.php' == $pagenow) || (is_multisite() && 'settings.php' == $pagenow)) && !empty($_GET['udm_refresh'])) {
			if ($this->plug_updatechecker) $this->plug_updatechecker->checkForUpdates();
		}

		include_once(UDADDONS2_DIR.'/options.php');
		$this->options = new UpdraftPlusAddOns_Options2($this->slug, __('UpdraftPlus Addons', 'updraftplus'), $this->url);

	}

	public function addons_admin_url() {
		return UpdraftPlus_Options::admin_page().'?page='.UDADDONS2_PAGESLUG.'&tab=addons';
	}

	/**
	 * Funnelling through here a) allows for future flexibility and b) allows us to migrate elegantly from the previous non-MU-friendly setup
	 *
	 * @param  string $option
	 * @return array
	 */
	public function get_option($option) {
		$val = get_site_option($option);
		// On multisite, migrate options into the site options
		if (false === $val && is_multisite()) {
			$blog_id = get_current_blog_id();
			if ($blog_id>1) {
				$val = get_option($option);
				if (false !== $val) {
					delete_option($option);
					update_site_option($option, $val);
					return $val;
				}
			}
			// $val is still false
			switch_to_blog(1);
			$val = get_option($option);
			if (false !== $val) {
				delete_option($option);
				update_site_option($option, $val);
			}
			restore_current_blog();
		}
		return $val;
	}

	/**
	 * Remove and update a site option
	 *
	 * @param String $option
	 * @param Mixed	 $val
	 *
	 * @return Boolean - true if the option was successfully set; otherwise false
	 */
	public function update_option($option, $val) {
		delete_site_option($option);
		return update_site_option($option, $val);
	}

	public function deinstall_udaddons() {
		$del = '<a href="' . wp_nonce_url('plugins.php?action=delete-selected&amp;checked[]=updraftplus-addons/updraftplus-addons.php&amp;plugin_status=all&amp;paged=1&amp;s=', 'bulk-plugins') . '" title="' . esc_attr__('Delete plugin') . '" class="delete">' . 'delete the UpdraftPlus Addons Manager plugin' . '</a>';
		$this->show_admin_warning('You can '.$del.' - it is obsolete (all of its functions, including your add-ons, are now included in the main UpdraftPlus plugin obtained from updraftplus.com).');
	}

	public function show_admin_warning($message, $class = "updated") {
		echo '<div class="updraftmessage '.esc_attr($class).'"><p>'.$message.'</p></div>';// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- needs to be presented in html
	}

	/**
	 * Remove any existing updates detected
	 *
	 * @param  array $updates
	 * @return array
	 */
	public function site_transient_update_plugins($updates) {
		if (!is_object($updates) || empty($this->plugin_file)) return $updates;
		if (isset($updates, $updates->response, $updates->response[$this->plugin_file]))
			unset($updates->response[$this->plugin_file]);
		return $updates;
	}

	/**
	 * We want to lessen the number of automatic checks if an update is already known to be available
	 *
	 * @param  string $shouldcheck Should check if there are updates
	 * @param  string $lastcheck   Last update check
	 * @param  string $checkperiod Period to check
	 * @return boolean
	 */
	public function puc_check_now($shouldcheck, $lastcheck, $checkperiod) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Filter use
	
		// Skip checks immediately after a WP upgrade. This action has existed since WP 4.4. Since we're just trying to reduce server load spikes when WP core automatic security upgrades happen, that is adequate.
		if (did_action('pre_auto_update')) return false;
	
		global $wp_current_filter;
		
		/*
		 * Return without any changes if no check was going to happen anyway; or, if it was, if any of these conditions match:
		 * - We have no checker object
		 * - There hasn't been a last check
		 * - We're on the update-core.php page
		 * - We're not in a cron context
		 */
		if (true !== $shouldcheck || empty($this->plug_updatechecker) || 0 == $lastcheck || (is_array($wp_current_filter) && in_array('load-update-core.php', $wp_current_filter)) || !defined('DOING_CRON')) return $shouldcheck;
		
		// i.e. return unchanged result (i.e. do check if you were going to) if no update is available
		if (null === $this->plug_updatechecker->getUpdate()) return $shouldcheck;

		// So, now we know an update is available. In this situation, we reduce checks.
		
		$days_since_check = max(round((time() - $lastcheck)/86400), 1);
		if ($days_since_check > 10000) return true;

		// Suppress checks on days 2, 4, 5, 7 and then every day except multiples of 7.
		if (2 == $days_since_check || 4 == $days_since_check || 5 == $days_since_check || 7 == $days_since_check || ($days_since_check >= 7 && 0 != $days_since_check % 7)) return false;

		return true;
	}

	/**
	 * Send a licence claim to the licensing server
	 *
	 * @param String $key - the add-on being claimed
	 *
	 * @return WP_Error|Array - body as returned by wp_remote_post(), after JSON-decoding
	 */
	private function claim_addon($key) {
	
		$options = $this->get_option(UDADDONS2_SLUG.'_options');

		$post_array = array(
			'e' => $options['email'],
			'sid' => $this->siteid(),
			'sn' => base64_encode(get_bloginfo('name')),
			'su' => base64_encode(home_url()),
			'key' => $key,
			'si2' => json_encode($this->get_site_info()),
			'response_format' => 'json'
		);

		$result = wp_remote_post($this->url.'/plugin-info/?udm_action=claimaddon',
			array(
				'timeout' => 15,
				'body' => $post_array
			)
		);

		if (!is_wp_error($result) && isset($result['body']) && null !== ($response = json_decode($result['body'])) && is_object($response) && !empty($response->code) && 'OK' === $response->code) {
			// Remove the password from the stored settings, for security. We have confirmed that we can authenticate via token (SID) - which is valid for approx. a week (the user can re-enter the password if he needs to)
			unset($options['password']);
			$this->update_option(UDADDONS2_SLUG.'_options', $options);
		} else {

			// Try again with password (old-style protocol)
			// The 'password' encoded here is the updraftplus.com password. See here: https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/
			if (!empty($options['password'])) {
			
				$post_array['p'] = base64_encode($options['password']);

				$result = wp_remote_post($this->url.'/plugin-info/?udm_action=claimaddon',
					array(
						'timeout' => 15,
						'body' => $post_array
					)
				);

				if (!is_wp_error($result) && isset($result['body'])) $response = json_decode($result['body']);
			}
		}

		return $response;

	}

	/**
	 * Handles the AJAX request to authenticate the user and claim all available add-ons.
	 *
	 * Retrieves the email and password from the POST request, stores them in plugin options,
	 * then attempts to claim all available add-ons using the provided credentials.
	 * Returns the result as a JSON response.
	 *
	 * @return void
	 */
	public function ajax_login_and_claim_addons() {
		list($slug, $nonce) = array_values(UpdraftPlus_Manipulation_Functions::fetch_superglobal_array(
			array('post', 'slug'),
			array('post', 'nonce')
		));
		if ('updraftplus' !== $slug) return;
		if (!wp_verify_nonce($nonce, 'udmupdater-ajax-nonce') || !UpdraftPlus_Options::user_can_manage()) die('Security check');

		$credentials = array(
			'email' => UpdraftPlus_Manipulation_Functions::fetch_superglobal('post', 'email', '', true),
			'password' => UpdraftPlus_Manipulation_Functions::fetch_superglobal('post', 'password', '', true),
		);

		$this->update_option(UDADDONS2_SLUG . '_options', $credentials);
		$response = $this->claim_addon('all');

		wp_send_json($response);
	}

	/**
	 * Called by the WP action wp_ajax_udaddons_claimaddon
	 */
	public function ajax_udaddons_claimaddon() {

		$nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
		if (!wp_verify_nonce($nonce, 'udmanager-nonce') || empty($_POST['key'])) die('Security check');

		$key = $_POST['key'];
		
		$result = $this->claim_addon($key);
 
		if (is_wp_error($result)) {
			echo esc_html__('Errors occurred:', 'updraftplus').'<br>';
			show_message($result);
		} elseif (is_object($result)) {
		
			if ((!defined('UPDRAFTPLUS_ADDONS_QUICK_INSTALL') || !UPDRAFTPLUS_ADDONS_QUICK_INSTALL) && !empty($result->data->files)) {
			
				$all_addons = array();
				
				if (is_dir(UPDRAFTPLUS_DIR.'/addons') && $dir_handle = opendir(UPDRAFTPLUS_DIR.'/addons')) {
					while (false !== ($e = readdir($dir_handle))) {
						if (is_file(UPDRAFTPLUS_DIR.'/addons/'.$e) && preg_match('/\.php$/', $e)) {
							$all_addons[] = $e;
						}
					}
				}
				
				foreach ($result->data->files as $file => $data) {
					if (false !== strpos($file, '..')) continue;
					if (preg_match('#^addons/(.*\.php)$#', $file, $matches)) {
						$all_addons[] = $matches[1];
					}
				}
			
				$all_addons = array_unique($all_addons);
				
				$new_sub_version = ('all' == $key || count($all_addons) > 15 ) ? count($all_addons) + 1 : count($all_addons);
				
				foreach ($result->data->files as $file => $data) {
				
					if (false !== strpos($file, '..')) continue;
				
					if ('updraftplus.php' != $file && !preg_match('#^addons/.*\.php$#', $file)) continue;

					if (false == ($decompressed = gzuncompress(base64_decode($data)))) continue;
					
					// Check the basic sanity of the incoming data
					$start = substr($decompressed, 0, 128);
					
					if ('updraftplus.php' == $file && false === strpos($start, 'Plugin Name: UpdraftPlus')) continue;
					
					if (preg_match('#^addons/.*\.php$#', $file) && false === strpos($start, 'UpdraftPlus Addon:')) continue;
					
					if ('updraftplus.php' == $file) $decompressed = preg_replace('/\nVersion: \d+\.(\d+\.\d+)/', "\n".'Version: 2.$1.'.$new_sub_version, $decompressed, 1);

					if (false == file_put_contents(UPDRAFTPLUS_DIR.'/'.$file, $decompressed)) {
						$addons_written = false;
						break;
					}
					
					$addons_written = true;
				}
			}
		
			$result->check_updates = true;
			
			if (!empty($addons_written)) $result->addons_written = true;
		
			// If the results included update information, then store that
			if (!empty($result->data) && !empty($result->data->plugin_info) && !empty($this->plug_updatechecker)) {

				// e.g. Puc_v4p9_Plugin_UpdateChecker
				$checker_class = get_class($this->plug_updatechecker);
				
				// Hopefully take off the 'Checker'. The setUpdate() call below wants a compatible version.
				$plugin_update_class = substr($checker_class, 0, strlen($checker_class)-7);
				
				if (class_exists($plugin_update_class) && is_callable(array($plugin_update_class, 'fromObject'))) {
				
					// $plugin_update_class::fromObject() is invalid syntax on PHP 5.2
					$plugin_update = call_user_func(array($plugin_update_class, 'fromObject'), $result->data->plugin_info);

					$update_checker = $this->plug_updatechecker;
					
					$installed_version = $update_checker->getInstalledVersion();

					if (null !== $installed_version) {
					
						$state = $update_checker->getUpdateState();
						$state->setLastCheckToNow()->setCheckedVersion($installed_version);
						$state->setUpdate($plugin_update);
						$state->save();
						
						$result->check_updates = false;
						
					}
					
				}
			
			}
			// Removed only because it is unnecessary
			unset($result->data);
			
			echo json_encode($result);
		} else {
			echo esc_html(__('Errors occurred:', 'updraftplus').' '.serialize($result));
		}

		die;

	}

	/**
	 * Return a reasonably unique ID for the site
	 *
	 * @return String
	 */
	public function siteid() {
		$sid = get_site_option(UDADDONS2_SLUG.'_siteid');
		if (!is_string($sid) || empty($sid)) {
			$sid = md5(wp_rand().microtime(true).home_url());
			update_site_option(UDADDONS2_SLUG.'_siteid', $sid);
		}
		return $sid;
	}

	/**
	 * Return site information
	 *
	 * @return Array - which can be json_encode()-ed.
	 */
	private function get_site_info() {
	
		global $wp_version, $updraftplus;
		
		include(ABSPATH.WPINC.'/version.php');
		
		$site_info = array(
			'wp' => $wp_version,
			'php' => PHP_VERSION,
			'multi' => is_multisite() ? 1 : 0,
			'mem' => ini_get('memory_limit'),
			'lang' => (string) get_locale()
		);
		
		// Since 3.7.0
		if (function_exists('wp_get_installed_translations')) {
			$all_translations = wp_get_installed_translations('plugins');
			if (isset($all_translations[$this->slug])) {
				foreach ($all_translations[$this->slug] as $locale => $tinfo) {
					$found_existing = false;
					if (isset($tinfo['PO-Revision-Date'])) {
						$found_existing = strtotime($tinfo['PO-Revision-Date']);
					}
					$site_info['trans'][$locale]['d'] = $found_existing;
				}
			}
		}
		
		if (is_a($updraftplus, 'UpdraftPlus') && isset($updraftplus->version)) {
			$site_info['ud'] = $updraftplus->version;
			if (class_exists('UpdraftPlus_Options')) $site_info['service'] = json_encode(UpdraftPlus_Options::get_updraft_option('updraft_service'));
		}
		
		return $site_info;
	}
	
	/**
	 * Modifies the query arguments on the updates request
	 *
	 * @param Array $args - unfiltered arguments
	 *
	 * @return Array - filtered arguments
	 */
	public function updater_queryargs_plugin($args) {
		if (!is_array($args)) return $args;

		$options = $this->get_option(UDADDONS2_SLUG.'_options');
		$email = isset($options['email']) ? $options['email'] : '';
		$args['udm_action'] = 'updateinfo';

		$args['sid'] = $this->siteid();
		$args['su'] = urlencode(base64_encode(home_url()));
		$args['sn'] = urlencode(base64_encode(get_bloginfo('name')));
		$args['slug'] = urlencode($this->slug);
		$args['e'] = urlencode($email);

		if (defined('UPDRAFTPLUS_ADDONS_SSL') && UPDRAFTPLUS_ADDONS_SSL == true) $args['ssl'] = 1;

		// Some information on the server calling. This can be used - e.g. if they have an old version of PHP/WordPress, then this may affect what update version they should be offered
		$args['si2'] = urlencode(base64_encode(json_encode($this->get_site_info())));

		// Unset a couple of values set by version 4.0+ of plugin-updates-checker
		unset($args['php']);
		unset($args['locale']);
		
		return $args;
	}

	/**
	 * This function, if ever changed, should be kept in sync with the same function in udmanager.php
	 *
	 * @param  String $file
	 * @return Boolean|Array
	 */
	private function get_addon_info($file) {
		if ($f = fopen($file, 'r')) {
			$key = "";
			$name = "";
			$description = "";
			$version = "";
			$shopurl = "";
			$latestchange = null;
			$lines_read = 0;
			while ($lines_read<10 && $line = @fgets($f)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
				if ("" == $key && preg_match('/Addon: ([^:]+):(.*)$/i', $line, $lmatch)) {
					$key = $lmatch[1];
					$name = $lmatch[2];
				} elseif ("" == $description && preg_match('/Description: (.*)$/i', $line, $lmatch)) {
					$description = $lmatch[1];
				} elseif ("" == $version && preg_match('/Version: (.*)$/i', $line, $lmatch)) {
					$version = $lmatch[1];
				} elseif ("" == $shopurl && preg_match('/Shop: (.*)$/i', $line, $lmatch)) {
					$shopurl = $lmatch[1];
				} elseif ("" == $latestchange && preg_match('/Latest Change: (.*)$/i', $line, $lmatch)) {
					$latestchange = $lmatch[1];
				}
				$lines_read++;
			}
			fclose($f);
			if ($key && $name && $description && $version) {
				return array('key' => $key, 'name' => $name, 'description' => $description, 'installedversion' => $version, 'shopurl' => $shopurl, 'latestchange' => $latestchange);
			}
		}
		return false;
	}

	private function get_default_addons() {
		return array(
			'noadverts' => array(
				'name' => 'Remove adverts',
				'description' => 'Removes all adverts from the control panel and emails',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'all' => array(
				'name' => 'All addons',
				'description' => 'Access to all UpdraftPlus add-ons',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'multisite' => array(
				'name' => 'WordPress Network (multisite) support',
				'description' => 'Adds support for WordPress Network (multisite) installations, allowing secure backup by the super-admin only',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'fixtime' => array(
				'name' => 'Fix Time',
				'description' => 'Allows you to specify the exact time at which backups will run',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'morefiles' => array(
				'name' => 'More Files',
				'description' => 'Allows you to backup WordPress core, and other files in your web space',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'sftp' => array(
				'name' => 'SFTP and FTPS and SCP',
				'description' => 'Allows SFTP and SCP as a cloud backup method, and encrypted FTP',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'dropbox-folders' => array(
				'name' => 'Dropbox Folders',
				'description' => 'Allows you to organise your backups into Dropbox sub-folders',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'morestorage' => array(
				'name' => 'Multiple storage destinations',
				'description' => 'Allows you to send a single backup to multiple destinations (e.g. Dropbox and Google Drive and Amazon)',
				'shopurl' => '/shop/updraftplus-premium/'
			),
			'webdav' => array(
				'name' => 'WebDAV support',
				'description' => 'Allows you to use the WebDAV and encrypted WebDAV protocols for remote backups',
				'shopurl' => '/shop/updraftplus-premium/'
			)
		);
	}

	private function get_local_addons($long_form = true) {

		$plugin_dir = WP_PLUGIN_DIR.'/'.$this->slug;

		if (!is_dir($plugin_dir.'/addons')) return array();
		$local_addons = array();
		if ($dir_handle = @opendir($plugin_dir.'/addons')) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
			while (false !== ($e = readdir($dir_handle))) {
				if (is_file($plugin_dir.'/addons/'.$e) && preg_match('/^(.*)\.php$/i', $e, $matches)) {
					$addon = $this->get_addon_info($plugin_dir.'/addons/'.$e);
					if (is_array($addon)) {
						$key = $addon['key'];
						if ($long_form) {
							$local_addons[$key] = $addon;
						} else {
							$local_addons[] = $key;
						}
					}
				}
			}
		}

		return $local_addons;

	}

	/**
	 * Get a list of available add-ons
	 *
	 * @return Array
	 */
	public function get_available_addons() {

		// Cached in this object?
		if (is_array($this->available_addons)) return $this->available_addons;

		// The remote list may be cached in a site transient
		$potential_array = get_site_transient('upaddons_remote');
		if (false == $this->debug && is_array($potential_array) && isset($potential_array['all'])) {
			$this->remote_addons = $potential_array;
			$remote_addons = $potential_array;
		} else {

			$url = $this->url.'/plugin-info/?udm_action=listaddons&response_format=json';

			$result = wp_remote_get($url, array('timeout' => 15));
			
			if (!is_wp_error($result) & false !== $result) {
				$response = json_decode($result['body'], true);

				$remote_addons = array();

				if (is_array($response) && isset($response['addons'])) {
					$addons = $response['addons'];
					// One more sanity check
					if (isset($addons['all'])) {
						$remote_addons = $addons;
						// Cache it
						$this->remote_addons = $addons;
						set_site_transient('upaddons_remote', $addons, 14400);
					}
				}
			} else {
				// Populate with default
				$remote_addons = $this->get_default_addons();
			}

		}

		// Perhaps we have some installed that have been obsoleted/removed upstream

		$installed_addons = $this->get_local_addons();

		$all_addons = array();
		foreach ($remote_addons as $key => $addon) {
			// Can then get over-ridden
			$addon['installed'] = false;
			$all_addons[$key] = $addon;
		}

		foreach ($installed_addons as $key => $addon) {
			if (isset($all_addons[$key])) {
				// The remote info over-writes all else
				$newaddon = $all_addons[$key];
				$newaddon['installed'] = true;
				$newaddon['installedversion'] = $addon['installedversion'];
				
			} else {
				$newaddon = $addon;
				if (!empty($newaddon['installedversion'])) $newaddon['installed'] = true;
			}
			$all_addons[$key] = $newaddon;
		}

		$this->available_addons = $all_addons;
		return $all_addons;

	}

	/**
	 * This function will get the connection status
	 *
	 * @return boolean|WP_Error - returns true if successful
	 */
	public function connection_status() {

		$options = $this->get_option(UDADDONS2_SLUG.'_options');

		$try_siteid = false;

		$oval = is_object($this->plug_updatechecker) ? get_site_option($this->plug_updatechecker->optionName, null) : null;
		// Detect the case where the password has been removed
		if (is_object($oval) && !empty($oval->lastCheck) && time()-$oval->lastCheck < 86400*8) {
			$try_siteid = $this->siteid();
		}

		// Username and password set up?
		if (empty($options['email']) || (empty($options['password']) && false == $try_siteid)) return new WP_Error('blank_details', __('You need to supply both an email address and a password', 'updraftplus'));

		// Hash will change if the account changes (password change is handled by the options filter)
		$ehash = substr(md5($options['email']), 0, 23);
		$trans = get_site_transient('udaddons_connect_'.$ehash);

		// In debug mode, we don't cache
		if (true !== $this->debug && empty($_GET['udm_refresh']) && is_array($trans)) {
			if (isset($trans['myaddons']) && is_array($trans['myaddons'])) {
				$this->user_addons = $trans['myaddons'];
			}
			if (isset($trans['availableaddons']) && is_array($trans['availableaddons'])) {
				$this->remote_addons = $trans['availableaddons'];
			}
			if (isset($trans['support']) && is_array($trans['support'])) {
				$this->user_support = $trans['support'];
			}
			return true;
		}

		$password = isset($options['password']) ? $options['password'] : '';

		$connect = $this->connect($options['email'], $password);

		if (is_wp_error($connect)) return $connect;
		if (false === $connect) return new WP_Error('failed_connection', __('We failed to successfully connect to UpdraftPlus.Com', 'updraftplus'));

		if (!is_bool($connect)) return new WP_Error('bad_response', __('UpdraftPlus.Com responded, but we did not understand the response', 'updraftplus'));

		return true;

	}

	/**
	 * Returns either true (in which case the add-ons array is populated), or a WP_Error
	 *
	 * @param  string $email    Email for the remote post array
	 * @param  string $password Password for the remote post array
	 * @return boolean
	 */
	private function connect($email, $password) {

		global $updraftplus;
	
		// Use previous response, if available
		if (is_array($this->user_addons) && count($this->user_addons) > 0) return true;

		$url = $this->url.'/plugin-info/?udm_action=connect';

		// The 'password' encoded here is the updraftplus.com password. See here: https://updraftplus.com/faqs/tell-me-about-my-updraftplus-com-account/. Note - it may be empty if the user removed their password.
		$result = wp_remote_post($url,
			array(
				'timeout' => 15,
				'body' => array(
					'e' => $email,
					'p' => base64_encode($password),
					'sid' => $this->siteid(),
					'sn' => base64_encode(get_bloginfo('name')),
					'su' => base64_encode(home_url()),
					'f' => 2
				)
			)
		);

		if (is_wp_error($result) || false === $result) return $result;

		$code = wp_remote_retrieve_response_code($result);
		
		if ($code >= 400) {
		
			$message = __('An error response was received; HTTP code:', 'updraftplus').' '.$code;
			
			$headers = wp_remote_retrieve_headers($result);
			
			if (!empty($headers['cf-ray'])) {
				$message .= ' CF-Ray: '.$headers['cf-ray'];
			}
			
			if (403 == $code) {
				$ip_addr = $updraftplus->get_outgoing_ip_address(true);
				if (false !== $ip_addr && false !== filter_var($ip_addr, FILTER_VALIDATE_IP)) {
					$message .= '  IP: '.htmlspecialchars($ip_addr);
					
					$message .= '<br>'.__('This most likely means that you share a webserver with a hacked website that has been used in previous attacks.', 'updraftplus').'<br> <a href="https://updraftplus.com/unblock-ip-address/" target="_blank">'.__('To remove any block, please go here.', 'updraftplus').'</a> '.__('Your IP address:', 'updraftplus').' '.htmlspecialchars($ip_addr);
					
				}
			}
			
			return new WP_Error('error_response', $message, $result);
		}
		
		$response = json_decode($result['body'], true);

		if (!is_array($response) || !isset($response['updraftpluscom']) || !isset($response['loggedin'])) {
			$ser_resp = htmlspecialchars(serialize($response));
			if (preg_match('/has banned your IP address \(([\.:0-9a-f]+)\)/', $response, $matches)) {
				return new WP_Error('banned_ip', sprintf(__("UpdraftPlus.com has responded with 'Access Denied'.", 'updraftplus').'<br>'.__("It appears that your web server's IP Address (%s) is blocked.", 'updraftplus').' '.__('This most likely means that you share a webserver with a hacked website that has been used in previous attacks.', 'updraftplus').'<br> <a href="https://updraftplus.com/unblock-ip-address/" target="_blank">'.__('To remove any block, please go here.', 'updraftplus').'</a> ', $matches[1]));
			} else {
				if (null === $ser_resp) {
					return new WP_Error('unknown_response', __('No response data was received.', 'updraftplus').' '.__('This usually indicates a network connectivity issue (e.g. an outgoing firewall or overloaded network) between this site and UpdraftPlus.com.', 'updraftplus'));
				} else {
					return new WP_Error('unknown_response', sprintf(__('UpdraftPlus.Com returned a response which we could not understand (data: %s)', 'updraftplus'), $ser_resp));
				}
			}
		}

		switch ($response['loggedin']) {
			case 'connected':
				if (isset($response['myaddons']) && is_array($response['myaddons'])) {
					$this->user_addons = $response['myaddons'];
				}
				if (isset($response['availableaddons']) && is_array($response['availableaddons'])) {
					$this->remote_addons = $response['availableaddons'];
					set_site_transient('upaddons_remote', $this->remote_addons, 14400);
				}
				if (isset($response['support']) && is_array($response['support'])) {
					$this->user_support = $response['support'];
				}
				$ehash = substr(md5($email), 0, 23);

				set_site_transient('udaddons_connect_'.$ehash, $response, 7200);

				// Now, trigger an update check, since things may have changed
				if ($this->plug_updatechecker) $this->plug_updatechecker->checkForUpdates();
				break;

			case 'authfailed':
				$ehash = substr(md5($email), 0, 23);
				delete_site_transient('udaddons_connect_'.$ehash);
				if (!empty($response['authproblem'])) {
					if ('invalidpassword' == $response['authproblem']) {
						$authfail_error = new WP_Error('authfailed', __("Your email is valid, but your password wasn't recognised.", 'updraftplus').'<br>');
						if (time() < strtotime('2026-01-01 00:00:00')) $authfail_error->add('authfailed', __('Some users were asked to reset their passwords as part of a recent website migration.', 'updraftplus').'<br>');
						// translators: %s: The reset password link
						$authfail_error->add('authfailed', sprintf(__('Try again, or %s before connecting again.', 'updraftplus'), '<a href="'.$updraftplus->get_url('lost-password').'">'.__('reset your password', 'updraftplus').'</a>'));
						return $authfail_error;
					} elseif ('invaliduser' == $response['authproblem']) {
						return new WP_Error('authfailed', __('You entered an email address that was not recognised by UpdraftPlus.Com', 'updraftplus'));
					}
				}
				return new WP_Error('authfailed', __('Your email address and password were not recognised by UpdraftPlus.Com', 'updraftplus'));
				break;

			default:
				return new WP_Error('unknown_response', __('UpdraftPlus.Com returned a response, but we could not understand it', 'updraftplus'));
				break;
		}

		return true;

	}
}
