====================================================================
 Migrador y respaldador de cuentas IMAP
====================================================================

Este programa copia o migra el contenido completo de una cuenta de
correo IMAP (carpetas, mensajes, adjuntos, flags y fechas) desde un
servidor origen (A) hacia un servidor destino (B).

Puede usarse tanto para migrar una cuenta a un servidor nuevo como
para mantener un respaldo periódico de una cuenta en otro servidor.

El programa NUNCA borra, mueve ni modifica mensajes en el servidor
origen.

--------------------------------------------------------------------
1. Requisitos
--------------------------------------------------------------------

- Python 3.10 o superior.
- No se requieren dependencias externas (solo librería estándar).

--------------------------------------------------------------------
2. Creación del entorno virtual
--------------------------------------------------------------------

Linux / macOS:

    python3 -m venv python-env
    source python-env/bin/activate

Windows:

    python -m venv python-env
    python-env\Scripts\activate

--------------------------------------------------------------------
3. Instalación de dependencias
--------------------------------------------------------------------

    pip install --upgrade pip
    pip install -r requirements.txt

(requirements.txt no declara dependencias externas: todo el programa
usa la librería estándar de Python.)

--------------------------------------------------------------------
4. Ejecución
--------------------------------------------------------------------

Ejemplo básico (las contraseñas se piden de forma interactiva si se
omiten):

    python3 imap_migrate.py \
        --aserver mail.oldserver.com \
        --auser usuario@dominio.com \
        --bserver mail.newserver.com \
        --buser usuario@dominio.com

Ejemplo completo, con contraseñas por parámetro:

    python3 imap_migrate.py \
        --aserver imap.servidor-a.com --aport 993 \
        --auser usuario@dominio.com --apassword 'passwordA' \
        --bserver imap.servidor-b.com --bport 993 \
        --buser usuario@dominio.com --bpassword 'passwordB'

Ejemplo usando una IP directa pero validando el certificado TLS
contra el nombre de host real (útil cuando el DNS no resuelve o se
quiere evitar la resolución DNS):

    python3 imap_migrate.py \
        --aserver mail.oldserver.com --aip 203.0.113.10 \
        --auser usuario@dominio.com \
        --bserver mail.newserver.com \
        --buser usuario@dominio.com

Ejemplo con servidor destino de certificado autofirmado (ver sección
6 para la advertencia de seguridad):

    python3 imap_migrate.py \
        --aserver mail.oldserver.com --auser usuario@dominio.com \
        --bserver mail.interno.local --buser usuario@dominio.com \
        --b-no-verify-tls

--------------------------------------------------------------------
5. Parámetros disponibles
--------------------------------------------------------------------

Servidor origen (A):
    --aserver           Host del servidor IMAP origen (obligatorio)
    --aport             Puerto (por defecto 993)
    --auser             Usuario/cuenta en el servidor origen (obligatorio)
    --apassword         Password (si se omite, se solicita interactivamente
                        o se toma de la variable de entorno IMAP_A_PASSWORD)
    --adomain           Dominio lógico de la cuenta (informativo / uso
                        futuro para migración de múltiples cuentas)
    --aip               IP a la que conectar, usando --aserver como
                        nombre de host para la validación TLS
    --a-no-verify-tls   Deshabilita la verificación de certificado TLS
                        SOLO para el servidor origen (inseguro)
    --a-no-ssl          Conecta sin SSL/TLS al servidor origen (inseguro)

Servidor destino (B):
    --bserver, --bport, --buser, --bpassword, --bdomain, --bip,
    --b-no-verify-tls, --b-no-ssl
        Mismo significado que los anteriores, aplicados al servidor
        destino. La contraseña también puede tomarse de la variable
        de entorno IMAP_B_PASSWORD.

Generales:
    --no-verify-tls     Deshabilita la verificación de certificado TLS
                        en AMBOS servidores (inseguro). Muestra una
                        advertencia de seguridad en consola y en el log.
    --timeout           Timeout de conexión en segundos (por defecto 30)
    --retries           Número de reintentos ante errores de red/IMAP
                        (por defecto 3)
    --state-file        Archivo de estado de la migración (por defecto
                        migration-state.json)
    --log-dir           Directorio de logs (por defecto logs/)
    --header-batch-size Cantidad de mensajes cuyos encabezados se
                        analizan por cada lote de red (por defecto 500)
    --verbose           Muestra en consola el mismo detalle que se
                        registra en el archivo de log
    -h, --help          Muestra la ayuda completa

--------------------------------------------------------------------
6. Certificados autofirmados / servidores internos
--------------------------------------------------------------------

Por defecto el programa valida los certificados TLS de ambos
servidores. Si alguno usa un certificado autofirmado (típico en
servidores internos), se puede deshabilitar la validación con:

    --no-verify-tls          (para ambos servidores)
    --a-no-verify-tls        (solo para el servidor origen)
    --b-no-verify-tls        (solo para el servidor destino)

Al usar cualquiera de estas opciones se imprime y registra una
advertencia de seguridad explícita. Úsese solo con servidores de
confianza.

--------------------------------------------------------------------
7. Cómo reanudar / re-ejecutar una migración incremental
--------------------------------------------------------------------

El programa mantiene un archivo de estado (por defecto
"migration-state.json" en el directorio de trabajo) con, por cada
carpeta:

    - el UID de origen hasta el cual ya se analizó de forma segura;
    - la huella (fingerprint, basada en Message-ID o en tamaño+fecha)
      de cada mensaje ya copiado;
    - el UIDVALIDITY visto la última vez.

Para reanudar una migración interrumpida (por CTRL+C, pérdida de
conexión, reinicio del servidor, etc.) o para hacer una nueva pasada
incremental (por ejemplo, para respaldar los mensajes nuevos desde la
última ejecución), simplemente se vuelve a ejecutar el mismo comando
apuntando al mismo --state-file:

    python3 imap_migrate.py --aserver ... --auser ... --bserver ... --buser ...

El programa detectará automáticamente qué mensajes ya fueron copiados
y solo transferirá los mensajes nuevos o los que quedaron pendientes
por un error anterior. Si un mensaje falló en una ejecución anterior,
se reintenta en la siguiente ejecución sin volver a analizar toda la
carpeta desde cero.

Si el UIDVALIDITY de una carpeta cambia en el servidor origen (esto
puede pasar tras una reconstrucción del buzón), el programa vuelve a
escanear esa carpeta completa, pero sigue evitando duplicados gracias
a que la huella de cada mensaje se basa principalmente en su
Message-ID.

--------------------------------------------------------------------
8. Cómo detener correctamente una migración
--------------------------------------------------------------------

Presionar CTRL+C durante la ejecución hace que el programa:

    1. termine de forma segura la operación IMAP en curso;
    2. guarde el estado de la migración;
    3. cierre las conexiones con ambos servidores;
    4. muestre las estadísticas parciales acumuladas;
    5. finalice.

La siguiente ejecución continuará desde el punto en que se quedó.

--------------------------------------------------------------------
9. Dónde están los logs
--------------------------------------------------------------------

Los logs se escriben en el directorio indicado por --log-dir (por
defecto "logs/"), con un archivo por día:

    logs/migration-2026-09-09.log

El log incluye inicio de ejecución, conexiones, reconexiones,
creación de carpetas, mensajes copiados/omitidos, errores, reintentos
y el resumen final. Nunca se registran contraseñas.

--------------------------------------------------------------------
10. Dónde está el archivo de estado
--------------------------------------------------------------------

Por defecto: "migration-state.json" en el directorio desde el que se
ejecuta el programa (configurable con --state-file). Nunca contiene
contraseñas.

--------------------------------------------------------------------
11. Códigos de salida
--------------------------------------------------------------------

    0 = migración terminada correctamente
    1 = migración terminada con errores (ver el resumen final y el log)
    2 = error de parámetros
    3 = error de conexión con alguno de los servidores

--------------------------------------------------------------------
12. Ejecutar las pruebas
--------------------------------------------------------------------

Las pruebas usan únicamente "unittest" (librería estándar) y mocks;
no requieren servidores IMAP reales.

    python3 -m unittest discover -s tests -t .

--------------------------------------------------------------------
13. Estructura del proyecto
--------------------------------------------------------------------

    imap_migrate.py    Punto de entrada de línea de comandos
    config.py           Parseo de argumentos y configuración
    imap_client.py       Cliente IMAP (conexión, carpetas, fetch, append)
    migrator.py          Orquestador de la migración (análisis + copia)
    state.py             Persistencia del estado de migración
    fingerprint.py        Cálculo de huellas para detectar duplicados
    progress.py          Progreso en consola, ETA, resumen final
    logger.py            Configuración de logging
    utf7.py              Codificación UTF-7 modificada para nombres de carpeta
    requirements.txt
    Leame.txt
    logs/                Logs de ejecución
    tests/               Pruebas unitarias

--------------------------------------------------------------------
14. Migración de múltiples cuentas (extensión futura)
--------------------------------------------------------------------

Actualmente el programa migra una cuenta por ejecución. El diseño
(Migrator recibe un objeto de configuración por cuenta) permite
extenderlo fácilmente para leer un archivo "usuarios.csv" o
"usuarios.json" con varias cuentas y ejecutar la migración de cada
una en un bucle, sin cambios estructurales.
