array( 'label' => '247ChatMate fallback sender', 'status' => 'active', 'available' => true, 'description' => 'Active safe route. Sends through the site/WordPress mailer with 247ChatMate sender identity and Reply-To routing.', ), 'agency_proxy' => array( 'label' => 'Agency-owned email proxy', 'status' => 'architecture_locked', 'available' => false, 'description' => 'Architecture slot for an agency-controlled proxy. Endpoint and hashed token can be stored; live sending stays on fallback until a tested proxy module is enabled.', ), 'postmark' => array( 'label' => 'Postmark transactional sender', 'status' => 'architecture_locked', 'available' => false, 'description' => 'Architecture slot reserved for verified transactional delivery. Not selectable in this build.', ), 'brevo' => array( 'label' => 'Brevo automation sender', 'status' => 'architecture_locked', 'available' => false, 'description' => 'Architecture slot reserved for verified automation and campaign delivery. Not selectable in this build.', ), 'google_workspace' => array( 'label' => 'Google Workspace / Gmail SMTP', 'status' => 'architecture_locked', 'available' => false, 'description' => 'Architecture slot reserved for verified Google Workspace or Gmail SMTP delivery. Not selectable in this build.', ), 'custom_smtp' => array( 'label' => 'Custom SMTP sender', 'status' => 'architecture_locked', 'available' => false, 'description' => 'Architecture slot reserved for verified SMTP delivery. Not selectable in this build.', ), ); } } if (!function_exists('matewa_email_profile_provider_options')) { function matewa_email_profile_provider_options() { $routes = matewa_email_profile_provider_routes(); $options = array(); foreach ($routes as $key => $route) { $options[$key] = isset($route['label']) ? (string) $route['label'] : (string) $key; } return $options; } } if (!function_exists('matewa_email_profile_available_provider_options')) { function matewa_email_profile_available_provider_options() { $routes = matewa_email_profile_provider_routes(); $options = array(); foreach ($routes as $key => $route) { if (!empty($route['available'])) { $options[$key] = isset($route['label']) ? (string) $route['label'] : (string) $key; } } return $options; } } if (!function_exists('matewa_email_profile_normalise_provider')) { function matewa_email_profile_normalise_provider($provider) { $provider = sanitize_key((string) $provider); $legacy = array( 'postmark_later' => 'postmark', 'brevo_later' => 'brevo', 'google_later' => 'google_workspace', 'smtp_later' => 'custom_smtp', 'proxy_later' => 'agency_proxy', 'agency_proxy_later' => 'agency_proxy', ); if (isset($legacy[$provider])) { $provider = $legacy[$provider]; } $routes = matewa_email_profile_provider_routes(); if (!isset($routes[$provider])) { return 'fallback_247chatmate'; } // Only complete/available routes may become the active delivery route. if (empty($routes[$provider]['available'])) { return 'fallback_247chatmate'; } return $provider; } } if (!function_exists('matewa_email_profile_option_name')) { function matewa_email_profile_option_name($context) { $context = sanitize_key((string) $context); return in_array($context, matewa_email_profile_contexts(), true) ? 'matewa_email_profile_' . $context : 'matewa_email_profile_normal'; } } if (!function_exists('matewa_email_profile_default')) { function matewa_email_profile_default($context = 'normal') { $context = sanitize_key((string) $context); if ('agency' === $context) { return array( 'sender_name' => '', 'sender_email' => '', 'reply_to_email' => sanitize_email((string) get_option('matewa_agency_admin_email', '')), 'provider' => 'fallback_247chatmate', 'verification' => 'fallback_active', 'route_status' => 'active', 'use_for_setup' => '1', 'use_for_roundups' => '1', 'notes' => '', 'proxy_enabled' => '0', 'proxy_url' => '', 'proxy_route_id' => '', 'proxy_token_hash' => '', 'proxy_token_hint' => '', 'proxy_token_set' => '0', 'proxy_token_updated_at' => '', 'proxy_status' => 'not_configured', 'proxy_last_tested_at' => '', 'proxy_last_result' => '', 'proxy_fallback_mode' => 'fallback_on_fail', ); } return array( 'sender_name' => sanitize_text_field((string) get_option('matewa_business_name', '')), 'sender_email' => '', 'reply_to_email' => sanitize_email((string) get_option('matewa_leads_email', '')), 'provider' => 'fallback_247chatmate', 'verification' => 'fallback_active', 'route_status' => 'active', 'use_for_leads' => '1', 'use_for_summary' => '1', 'notes' => '', ); } } if (!function_exists('matewa_email_profile_sanitise_proxy_url')) { function matewa_email_profile_sanitise_proxy_url($url) { $url = trim((string) $url); if ('' === $url) { return ''; } $url = esc_url_raw($url, array('https')); if ('' === $url) { return ''; } $scheme = wp_parse_url($url, PHP_URL_SCHEME); if ('https' !== strtolower((string) $scheme)) { return ''; } return $url; } } if (!function_exists('matewa_email_profile_hash_proxy_token')) { function matewa_email_profile_hash_proxy_token($plain_token) { $plain_token = trim((string) $plain_token); if ('' === $plain_token) { return ''; } if (function_exists('wp_hash_password')) { return wp_hash_password($plain_token); } return password_hash($plain_token, PASSWORD_DEFAULT); } } if (!function_exists('matewa_email_profile_proxy_status_label')) { function matewa_email_profile_proxy_status_label($profile) { $profile = is_array($profile) ? $profile : array(); $proxy_url = isset($profile['proxy_url']) ? trim((string) $profile['proxy_url']) : ''; $token_set = !empty($profile['proxy_token_set']) && '1' === (string) $profile['proxy_token_set']; if ('' === $proxy_url) { return 'Not configured'; } if (!$token_set) { return 'Endpoint stored — token needed'; } return 'Proxy details stored — fallback still live'; } } if (!function_exists('matewa_email_profile_sanitise')) { function matewa_email_profile_sanitise($context, $raw) { $context = sanitize_key((string) $context); $raw = is_array($raw) ? $raw : array(); $defaults = matewa_email_profile_default($context); $routes = matewa_email_profile_provider_routes(); $sender_name = isset($raw['sender_name']) ? sanitize_text_field((string) $raw['sender_name']) : (string) $defaults['sender_name']; $sender_email = isset($raw['sender_email']) ? sanitize_email((string) $raw['sender_email']) : ''; $reply_to = isset($raw['reply_to_email']) ? sanitize_email((string) $raw['reply_to_email']) : (string) $defaults['reply_to_email']; $provider = isset($raw['provider']) ? matewa_email_profile_normalise_provider($raw['provider']) : 'fallback_247chatmate'; $route_status = isset($routes[$provider]['status']) ? (string) $routes[$provider]['status'] : 'active'; $profile = array( 'sender_name' => $sender_name, 'sender_email' => is_email($sender_email) ? $sender_email : '', 'reply_to_email' => is_email($reply_to) ? $reply_to : '', 'provider' => $provider, 'verification' => ('fallback_247chatmate' === $provider) ? 'fallback_active' : 'not_verified', 'route_status' => $route_status, 'notes' => isset($raw['notes']) ? sanitize_textarea_field((string) $raw['notes']) : '', ); if ('agency' === $context) { $existing_profile = get_option(matewa_email_profile_option_name('agency'), array()); $existing_profile = is_array($existing_profile) ? $existing_profile : array(); $proxy_url = isset($raw['proxy_url']) ? matewa_email_profile_sanitise_proxy_url($raw['proxy_url']) : (string) ($existing_profile['proxy_url'] ?? $defaults['proxy_url']); $proxy_route_id = isset($raw['proxy_route_id']) ? sanitize_text_field((string) $raw['proxy_route_id']) : (string) ($existing_profile['proxy_route_id'] ?? $defaults['proxy_route_id']); $proxy_route_id = substr($proxy_route_id, 0, 120); $proxy_enabled = array_key_exists('proxy_enabled', $raw) && !empty($raw['proxy_enabled']) ? '1' : '0'; $proxy_token_hash = (string) ($existing_profile['proxy_token_hash'] ?? ''); $proxy_token_hint = (string) ($existing_profile['proxy_token_hint'] ?? ''); $proxy_token_set = !empty($proxy_token_hash) ? '1' : (string) ($existing_profile['proxy_token_set'] ?? '0'); $proxy_token_updated_at = (string) ($existing_profile['proxy_token_updated_at'] ?? ''); if (!empty($raw['proxy_token_clear'])) { $proxy_token_hash = ''; $proxy_token_hint = ''; $proxy_token_set = '0'; $proxy_token_updated_at = ''; } elseif (isset($raw['proxy_token']) && '' !== trim((string) $raw['proxy_token'])) { $plain_proxy_token = trim((string) $raw['proxy_token']); $proxy_token_hash = matewa_email_profile_hash_proxy_token($plain_proxy_token); $proxy_token_hint = substr($plain_proxy_token, -4); $proxy_token_set = '' !== $proxy_token_hash ? '1' : '0'; $proxy_token_updated_at = (string) time(); } if ('1' === $proxy_enabled && '' !== $proxy_url && '1' === $proxy_token_set) { $proxy_status = 'configured_architecture_only'; } elseif ('' !== $proxy_url && '1' !== $proxy_token_set) { $proxy_status = 'token_needed'; } else { $proxy_status = 'not_configured'; } $profile['use_for_setup'] = array_key_exists('use_for_setup', $raw) ? (!empty($raw['use_for_setup']) ? '1' : '0') : (string) $defaults['use_for_setup']; $profile['use_for_roundups'] = array_key_exists('use_for_roundups', $raw) ? (!empty($raw['use_for_roundups']) ? '1' : '0') : (string) $defaults['use_for_roundups']; $profile['proxy_enabled'] = $proxy_enabled; $profile['proxy_url'] = $proxy_url; $profile['proxy_route_id'] = $proxy_route_id; $profile['proxy_token_hash'] = $proxy_token_hash; $profile['proxy_token_hint'] = sanitize_text_field($proxy_token_hint); $profile['proxy_token_set'] = $proxy_token_set; $profile['proxy_token_updated_at'] = $proxy_token_updated_at; $profile['proxy_status'] = $proxy_status; $profile['proxy_last_tested_at'] = sanitize_text_field((string) ($existing_profile['proxy_last_tested_at'] ?? '')); $profile['proxy_last_result'] = sanitize_text_field((string) ($existing_profile['proxy_last_result'] ?? '')); $profile['proxy_fallback_mode'] = 'fallback_on_fail'; } else { $profile['use_for_leads'] = array_key_exists('use_for_leads', $raw) ? (!empty($raw['use_for_leads']) ? '1' : '0') : (string) $defaults['use_for_leads']; $profile['use_for_summary'] = array_key_exists('use_for_summary', $raw) ? (!empty($raw['use_for_summary']) ? '1' : '0') : (string) $defaults['use_for_summary']; } return array_merge($defaults, $profile); } } if (!function_exists('matewa_email_profile_get')) { function matewa_email_profile_get($context = 'normal') { $context = sanitize_key((string) $context); $option = get_option(matewa_email_profile_option_name($context), array()); return matewa_email_profile_sanitise($context, is_array($option) ? $option : array()); } } if (!function_exists('matewa_email_profile_save')) { function matewa_email_profile_save($context, $raw) { $context = sanitize_key((string) $context); $profile = matewa_email_profile_sanitise($context, $raw); if (function_exists('matewa_direct_save_option_value')) { return matewa_direct_save_option_value(matewa_email_profile_option_name($context), $profile); } return update_option(matewa_email_profile_option_name($context), $profile, false); } } if (!function_exists('matewa_email_profile_status_label')) { function matewa_email_profile_status_label($profile) { $profile = is_array($profile) ? $profile : array(); $provider = isset($profile['provider']) ? matewa_email_profile_normalise_provider($profile['provider']) : 'fallback_247chatmate'; if ('fallback_247chatmate' === $provider) { if (!empty($profile['proxy_url']) && !empty($profile['proxy_token_set']) && '1' === (string) $profile['proxy_token_set']) { return 'Fallback active / proxy stored'; } return 'Fallback sender active'; } return 'Route locked'; } } if (!function_exists('matewa_email_profile_effective_sender_note')) { function matewa_email_profile_effective_sender_note($context = 'normal') { $profile = matewa_email_profile_get($context); $provider = isset($profile['provider']) ? matewa_email_profile_normalise_provider($profile['provider']) : 'fallback_247chatmate'; if ('fallback_247chatmate' === $provider) { if ('agency' === sanitize_key((string) $context)) { return 'Complete for this build: live emails use the safe 247ChatMate/default route. Agency proxy details can be stored with a hashed token, but fallback delivery remains live until the proxy route is deliberately enabled and tested.'; } return 'Complete for this build: emails use the safe 247ChatMate/default route and replies route through Reply-To where available.'; } return 'This route is locked until the provider verification module enables it.'; } } if (!function_exists('matewa_email_profile_architecture_status')) { function matewa_email_profile_architecture_status($context = 'normal') { $context = sanitize_key((string) $context); $profile = matewa_email_profile_get($context); $reply_to = isset($profile['reply_to_email']) ? sanitize_email((string) $profile['reply_to_email']) : ''; $sender_email = isset($profile['sender_email']) ? sanitize_email((string) $profile['sender_email']) : ''; $items = array( 'active_route' => array( 'label' => 'Active route', 'value' => '247ChatMate fallback sender', 'state' => 'ready', ), 'reply_to' => array( 'label' => 'Reply-To routing', 'value' => is_email($reply_to) ? $reply_to : 'Uses lead/customer route when available', 'state' => 'ready', ), 'custom_from' => array( 'label' => 'Custom From address', 'value' => is_email($sender_email) ? 'Stored only — not used as live From' : 'Locked off in this build', 'state' => 'locked', ), 'separation' => array( 'label' => ('agency' === $context) ? 'Agency/client separation' : 'Profile separation', 'value' => ('agency' === $context) ? 'Agency sender profile is separate from client lead inboxes' : 'Sender profile is separate from lead destination inbox', 'state' => 'ready', ), ); if ('agency' === $context) { $proxy_url = isset($profile['proxy_url']) ? trim((string) $profile['proxy_url']) : ''; $token_set = !empty($profile['proxy_token_set']) && '1' === (string) $profile['proxy_token_set']; $proxy_enabled = !empty($profile['proxy_enabled']) && '1' === (string) $profile['proxy_enabled']; $items['agency_proxy'] = array( 'label' => 'Agency email proxy', 'value' => ('' !== $proxy_url && $token_set && $proxy_enabled) ? 'Stored — fallback still live' : ('' !== $proxy_url ? 'Endpoint stored — token/setup needed' : 'Optional architecture slot'), 'state' => ('' !== $proxy_url && $token_set && $proxy_enabled) ? 'ready' : 'locked', ); $items['proxy_token'] = array( 'label' => 'Proxy token storage', 'value' => $token_set ? 'Hashed token stored' : 'No token stored', 'state' => $token_set ? 'ready' : 'locked', ); } return $items; } } if (!function_exists('matewa_email_profile_active_route_label')) { function matewa_email_profile_active_route_label($context = 'normal') { $profile = matewa_email_profile_get($context); $provider = isset($profile['provider']) ? matewa_email_profile_normalise_provider($profile['provider']) : 'fallback_247chatmate'; $routes = matewa_email_profile_provider_routes(); return isset($routes[$provider]['label']) ? (string) $routes[$provider]['label'] : '247ChatMate fallback sender'; } }