<?php
/**
 * Archivo desofuscado a partir de la versión generada por YAK Pro - Php Obfuscator
 * Obfuscator original: 2.0.14
 * Fecha original de ofuscación: 2024-10-14 15:47:24
 * GitHub: https://github.com/pk-fr/yakpro-po
 */

/**
 * LOG_FILE: Define el nombre del archivo de log.
 */
define("LOG_FILE", "decode.log");

/**
 * Función para registrar errores en un archivo de log.
 *
 * @param string $message
 */
function log_error($message) {
    $logLine = date("Y-m-d H:i:s") . " - " . $message . PHP_EOL;
    file_put_contents(LOG_FILE, $logLine, FILE_APPEND);
}

/**
 * Manejador de excepciones personalizado.
 *
 * @param Throwable $exception
 */
function exceptionHandler($exception) {
    log_error($exception->getMessage());
    // Se asume uso de sesión
    $_SESSION["error_message"] =
        "Se ha producido un error al procesar el mensaje. " .
        "Por favor, revisa los datos ingresados y vuelve a intentarlo. " .
        "Si el problema persiste, contacta al soporte técnico.";

    // Redirección a home (o donde se prefiera)
    header("Location: home.php");
    exit;
}

// Asigna la función de manejo de excepciones
set_exception_handler("exceptionHandler");

/**
 * Verifica que el cuerpo no esté vacío.
 *
 * @param string $body
 * @throws Exception
 */
function validate_body($body) {
    if (empty($body)) {
        throw new Exception(
            "Error: El cuerpo del mensaje está vacío. Asegúrate " .
            "de que el contenido no esté en blanco y vuelva a intentarlo."
        );
    }
}

/**
 * Verifica el tamaño mínimo y máximo del cuerpo (por defecto, entre 4 bytes y 1MB).
 *
 * @param string $content
 * @param int    $minSize
 * @param int    $maxSize
 * @throws Exception
 */
function validate_size($content, $minSize = 4, $maxSize = 1048576) {
    $length = strlen($content);
    if ($length < $minSize || $length > $maxSize) {
        throw new Exception(
            "Error: El tamaño del cuerpo no es válido. " .
            "Actualmente tiene {$length} caracteres, y debe estar " .
            "entre {$minSize} y {$maxSize} caracteres."
        );
    }
}

/**
 * Verifica los caracteres válidos en un cuerpo codificado Quoted-Printable.
 *
 * @param string $content
 * @throws Exception
 */
function validate_quoted_printable_characters($content) {
    // Lista de caracteres permitidos para quoted-printable.
    $allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ \t\r\n";
    $invalidChars = [];

    for ($i = 0; $i < strlen($content); $i++) {
        if (strpos($allowedChars, $content[$i]) === false) {
            $invalidChars[] = $content[$i];
        }
    }

    if (!empty($invalidChars)) {
        $invalidList = implode(", ", array_unique($invalidChars));
        throw new Exception(
            "Error: El cuerpo contiene caracteres no válidos para " .
            "quoted-printable: '{$invalidList}'. Asegúrate de que el contenido " .
            "solo contenga caracteres ASCII válidos (rango 0x20 al 0x7E)."
        );
    }
}

/**
 * Decodifica y valida Quoted-Printable.
 *
 * @param string $content
 * @return string
 * @throws Exception
 */
function decode_quoted_printable($content) {
    //validate_body($content);
    //validate_size($content);
    validate_quoted_printable_characters($content);

    $decoded = quoted_printable_decode($content);
    if ($decoded === false) {
        throw new Exception(
            "Error: No se pudo decodificar el cuerpo del mensaje como " .
            "quoted-printable. Verifica que el contenido '{$content}' " .
            "esté correctamente codificado."
        );
    }

    // Convierte el charset si fuera necesario
    $decoded = detect_and_convert_charset($decoded);
    return $decoded;
}

/**
 * Verifica y “limpia” un string base64 para asegurarse de que
 * contenga caracteres válidos para la especificación base64.
 *
 * @param string $content
 * @return string
 * @throws Exception
 */
function validate_and_sanitize_base64_characters($content) {
    // Conservar sólo caracteres base64 válidos: A-Z, a-z, 0-9, +, / y =
    $base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    // Eliminar saltos de línea, tabs, etc.
    $content = str_replace(["\r", "\n", "\t"], '', $content);

    // Base64 suele requerir longitud múltiplo de 4
    if (strlen($content) % 4 !== 0) {
        throw new Exception(
            "Error: El cuerpo debe ser un múltiplo de 4 caracteres para Base64. " .
            "Actualmente tiene " . strlen($content) . " caracteres. Asegúrate de que " .
            "la longitud sea correcta."
        );
    }

    $invalidChars = [];
    for ($i = 0; $i < strlen($content); $i++) {
        if (strpos($base64Chars, $content[$i]) === false) {
            $invalidChars[] = $content[$i];
        }
    }

    if (!empty($invalidChars)) {
        $invalidList = implode(", ", array_unique($invalidChars));
        throw new Exception(
            "Error: El cuerpo contiene caracteres no válidos para Base64: " .
            "'{$invalidList}'. Asegúrate de que solo incluya caracteres válidos: " .
            "A-Z, a-z, 0-9, +, / y =."
        );
    }

    return $content;
}

/**
 * Decodifica base64 validando y sanitizando los caracteres.
 *
 * @param string $content
 * @return string
 * @throws Exception
 */
function decode_base64($content) {
    // $content = validate_and_sanitize_base64_characters($content);
    //validate_body($content);
    //validate_size($content);

    $decoded = base64_decode($content, true);
    if ($decoded === false) {
        throw new Exception(
            "Error: No se pudo decodificar el cuerpo del mensaje en Base64. " .
            "El contenido '{$content}' no está correctamente codificado."
        );
    }

    // Convertir charset si fuera necesario
    $decoded = detect_and_convert_charset($decoded);
    return $decoded;
}

/**
 * Verifica si el contenido es válido UTF-16.
 *
 * @param string $content
 * @throws Exception
 */
function validate_utf16_characters($content) {
    // Comprueba la validez de la cadena en UTF-16
    if (!mb_check_encoding($content, "UTF-16")) {
        throw new Exception(
            "Error: El cuerpo contiene caracteres no válidos para UTF-16. " .
            "Verifica que esté correctamente codificado en UTF-16."
        );
    }
}

/**
 * Decodifica UTF-16 convirtiéndolo a UTF-8 y luego, si es necesario,
 * detecta el charset y lo convierte.
 *
 * @param string $content
 * @return string
 * @throws Exception
 */
function decode_utf16($content) {
    //validate_body($content);
    //validate_size($content);
    validate_utf16_characters($content);

    // Convierte de UTF-16 a UTF-8
    $decoded = mb_convert_encoding($content, "UTF-8", "UTF-16");
    if ($decoded === false) {
        throw new Exception(
            "Error: No se pudo decodificar el cuerpo del mensaje en UTF-16. " .
            "Asegúrate de que esté correctamente codificado en UTF-16."
        );
    }

    // Intentar detectar y convertir el charset si hay cabeceras que lo indiquen
    $decoded = detect_and_convert_charset($decoded);
    return $decoded;
}

/**
 * Detecta un charset a partir de la cadena (ej. `charset=ISO-8859-1`) y
 * la convierte a UTF-8 si es distinto.
 *
 * @param string $content
 * @return string
 * @throws Exception
 */
function detect_and_convert_charset($content) {
    // Busca si hay algo como charset=XXXXX en el texto
    if (preg_match("/charset=([\w-]+)/i", $content, $matches)) {
        $detectedCharset = $matches[1];

        // Si se detecta UTF-8, no convertir
        if (strtoupper($detectedCharset) === "UTF-8") {
            return $content;
        }

        // Convertir a UTF-8
        $converted = mb_convert_encoding($content, "UTF-8", $detectedCharset);

        // Verifica que realmente quedó en UTF-8
        if (!mb_check_encoding($converted, "UTF-8")) {
            throw new Exception(
                "Error: El charset '{$detectedCharset}' del cuerpo del mensaje " .
                "no es válido o no se puede convertir a UTF-8. Asegúrate de que " .
                "sea compatible con caracteres especiales, como tildes."
            );
        }

        return $converted;
    }

    // Si no se detecta charset, simplemente se retorna el contenido original
    return $content;
}

/**
 * Obtiene el cuerpo de un correo IMAP. Dependiendo del Content-Transfer-Encoding,
 * decodifica en base64, quoted-printable o UTF-16.
 *
 * @param resource $imapStream  Recurso de conexión IMAP
 * @param int      $msgNumber   Número del mensaje
 * @param object   $structure   Objeto con info de cabeceras (ContentTransferEncoding, etc.)
 * @return string  El cuerpo decodificado
 */
function get_email_body($imapStream, $msgNumber, $structure) {
    $mailStructure = imap_fetchstructure($imapStream, $msgNumber);
    $content = '';

    // Si no hay sub-partes, tratamos el cuerpo principal
    if (!isset($mailStructure->parts) || !count($mailStructure->parts)) {
        $content = imap_fetchbody($imapStream, $msgNumber, 1);

        if (isset($structure->ContentTransferEncoding)) {
            if (stripos($structure->ContentTransferEncoding, "base64") !== false) {
                try {
                    $content = decode_base64($content);
                } catch (Exception $e) {
                    log_error("Base64 decode error: " . $e->getMessage());
                }
            } elseif (stripos($structure->ContentTransferEncoding, "quoted-printable") !== false) {
                try {
                    $content = decode_quoted_printable($content);
                } catch (Exception $e) {
                    log_error("Quoted-printable decode error: " . $e->getMessage());
                }
            } elseif (stripos($structure->ContentTransferEncoding, "utf-16") !== false) {
                try {
                    $content = decode_utf16($content);
                } catch (Exception $e) {
                    log_error("UTF-16 decode error: " . $e->getMessage());
                }
            }
        }

    } else {
        // Si sí tiene partes, las iteramos
        $index = 0;
        while ($index < count($mailStructure->parts)) {
            $part = $mailStructure->parts[$index];

            if ($part->type == 0 || $part->type == 1) {
                $content = imap_fetchbody($imapStream, $msgNumber, $index + 1);

                if (isset($part->encoding)) {
                    try {
                        switch ($part->encoding) {
                            case 3: // base64
                                $content = decode_base64($content);
                                break;
                            case 4: // quoted-printable
                                $content = decode_quoted_printable($content);
                                break;
                            case 5: // asumiendo utf-16
                                $content = decode_utf16($content);
                                break;
                        }
                    } catch (Exception $e) {
                        log_error("Decoding part #{$index} error: " . $e->getMessage());
                    }
                }
            }
            $index++;
        }
    }

    return $content;
}

/**
 * Ejemplo de función que podría hacer un post-procesamiento adicional del cuerpo del email.
 *
 * @param string $body
 * @return string
 */
function process_email_body($body) {
    // Aquí podrías hacer limpieza adicional, parsear HTML, etc.
    return $body;
}
