<commit_before><?php

/**
 * SowerPHP
 * Copyright (C) SowerPHP (http://sowerphp.org)
 *
 * Este programa es software libre: usted puede redistribuirlo y/o
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
 * publicada por la Fundación para el Software Libre, ya sea la versión
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
 * misma.
 *
 * Este programa se distribuye con la esperanza de que sea útil, pero
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
 * obtener una información más detallada.
 *
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
 * junto a este programa.
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
 */

namespace sowerphp\core;

/**
 * Clase para interacturar con un servidor de correo IMAP
 * @author <NAME>, DeLaF (esteban[at]delaf.cl)
 * @version 2015-01-05
 */
class Network_Email_Imap
{

    protected $config = [
        'host' => 'localhost',
        'port' => 993,
        'ssl' => true,
        'sslcheck' => true,
        'folder' => 'INBOX',
    ]; ///< Configuración para IMAP
    protected $link = null; ///< Conexión al servidor IMAP

    /**
     * Constructor de la clase
     * @param config Arreglo con la configuración del servidor IMAP
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2020-07-06
     */
    public function __construct(array $config)
    {
        if (!isset($config['mailbox'])) {
            // definir puerto si no se pasó
            if (!isset($config['port']) and isset($config['ssl']) and !$config['ssl']) {
                $config['port'] = 143;
            }
            $this->config = array_merge($this->config, $config);
            // extraer puerto si se pasó en el host
            $url = parse_url($this->config['host']);
            if (isset($url['port'])) {
                $this->config['host'] = str_replace(':'.$url['port'], '', $this->config['host']);
                $this->config['port'] = $url['port'];
            }
            // definir mailbox
            $this->config['mailbox'] = $this->createMailbox();
        } else {
            $this->config = $config;
        }
        // conectar
        $this->link = @imap_open(
            $this->config['mailbox'],
            $this->config['user'],
            $this->config['pass']
        );
        if (!$this->isConnected()) {
            throw new \Exception(implode(' / ', imap_errors()));
        }
    }

    /**
     * Destructor de la clase
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function __destruct()
    {
        if (is_resource($this->link)) {
            imap_close($this->link);
        }
    }

    /**
     * Método que crea la dirección del Mailbox que se utilizará para las
     * funciones de IMAP
     * @param folder Carpeta en caso que se quira usar una diferente a la configuración de la conexión
     * @return Dirección completa para acceder al Mailbox en IMAP
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2021-07-20
     */
    private function createMailbox($folder = null)
    {
        $default_folder = !empty($this->config['folder']) ? $this->config['folder'] : 'INBOX';
        // si el mailbox no está asignado en la configuración se asigna con estándar INBOX como carpeta
        if (empty($this->config['mailbox'])) {
            $options = ['imap'];
            if ($this->config['ssl']) {
                $options[] = 'ssl';
                if (!$this->config['sslcheck']) {
                    $options[] = 'novalidate-cert';
                }
            }
            $this->config['mailbox'] = '{'.$this->config['host'].':'.$this->config['port'].'/'.implode('/',$options).'}'.$default_folder;
        }
        // se separa la carpeta del mailbox y se agrega la carpeta real que se busca
        $aux = explode('}', $this->config['mailbox']);
        if ($folder === null) {
            $folder = !empty($aux[1]) ? $aux[1] : $default_folder;
        }
        return $aux[0].'}'.$folder;
    }

    /**
     * Método que indica si se está o no conectado al servidor IMAP
     * @return =true si se está conectado
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function isConnected()
    {
        return (boolean)$this->link;
    }

    /**
     * Método que comprueba la casilla de correo
     * @return Arreglo con los datos de la casilla de correo
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function check()
    {
        return (array)imap_check($this->link);
    }

    /**
     * Método que entrega la cantidad de mensajes de la casilla de correo
     * @return Cantidad de mensajes en la casilla (leídos y no leídos)
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function countMessages()
    {
        return imap_num_msg($this->link);
    }

    /**
     * Método que entrega la cantidad de mensajes sin leer de la casilla de correo
     * @return Cantidad de mensajes sin leer
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function countUnreadMessages()
    {
        return imap_status($this->link, $this->createMailbox(), SA_ALL)->unseen;
    }

    /**
     * Método que entrega la información de estado de una casilla de correo
     * @return Arreglo con el estado de la casilla de correo
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function status()
    {
        return (array)imap_status($this->link, $this->createMailbox(), SA_ALL);
    }

    /**
     * Método que realiza una búsqueda sobre los mensajes de la casilla de correo
     * @param filter Criterios de búsqueda para la casilla
     * @return Arreglo con UIDs de los mensajes que coincidían con el filtro
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-03-14
     */
    public function search($filter = 'UNSEEN')
    {
        $uids = imap_search($this->link, $filter, SE_UID);
        return $uids===false ? [] : $uids;
    }

    /**
     * Método que entrega el número de mensaje a partir del UID
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2017-04-07
     */
    public function getMsgNumber($uid)
    {
        return imap_msgno($this->link, $uid);
    }

    /**
     * Método que entrega la información de la cabecera del mensaje
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2017-04-07
     */
    public function getHeaderInfo($uid)<commit_msg>Se mejora Imap::countUnreadMessages() para obtener sin leer con método alternativo<commit_after><?php

/**
 * SowerPHP
 * Copyright (C) SowerPHP (http://sowerphp.org)
 *
 * Este programa es software libre: usted puede redistribuirlo y/o
 * modificarlo bajo los términos de la Licencia Pública General Affero de GNU
 * publicada por la Fundación para el Software Libre, ya sea la versión
 * 3 de la Licencia, o (a su elección) cualquier versión posterior de la
 * misma.
 *
 * Este programa se distribuye con la esperanza de que sea útil, pero
 * SIN GARANTÍA ALGUNA; ni siquiera la garantía implícita
 * MERCANTIL o de APTITUD PARA UN PROPÓSITO DETERMINADO.
 * Consulte los detalles de la Licencia Pública General Affero de GNU para
 * obtener una información más detallada.
 *
 * Debería haber recibido una copia de la Licencia Pública General Affero de GNU
 * junto a este programa.
 * En caso contrario, consulte <http://www.gnu.org/licenses/agpl.html>.
 */

namespace sowerphp\core;

/**
 * Clase para interacturar con un servidor de correo IMAP
 * @author <NAME>, DeLaF (esteban[at]delaf.cl)
 * @version 2015-01-05
 */
class Network_Email_Imap
{

    protected $config = [
        'host' => 'localhost',
        'port' => 993,
        'ssl' => true,
        'sslcheck' => true,
        'folder' => 'INBOX',
    ]; ///< Configuración para IMAP
    protected $link = null; ///< Conexión al servidor IMAP

    /**
     * Constructor de la clase
     * @param config Arreglo con la configuración del servidor IMAP
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2020-07-06
     */
    public function __construct(array $config)
    {
        if (!isset($config['mailbox'])) {
            // definir puerto si no se pasó
            if (!isset($config['port']) and isset($config['ssl']) and !$config['ssl']) {
                $config['port'] = 143;
            }
            $this->config = array_merge($this->config, $config);
            // extraer puerto si se pasó en el host
            $url = parse_url($this->config['host']);
            if (isset($url['port'])) {
                $this->config['host'] = str_replace(':'.$url['port'], '', $this->config['host']);
                $this->config['port'] = $url['port'];
            }
            // definir mailbox
            $this->config['mailbox'] = $this->createMailbox();
        } else {
            $this->config = $config;
        }
        // conectar
        $this->link = @imap_open(
            $this->config['mailbox'],
            $this->config['user'],
            $this->config['pass']
        );
        if (!$this->isConnected()) {
            throw new \Exception(implode(' / ', imap_errors()));
        }
    }

    /**
     * Destructor de la clase
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function __destruct()
    {
        if (is_resource($this->link)) {
            imap_close($this->link);
        }
    }

    /**
     * Método que crea la dirección del Mailbox que se utilizará para las
     * funciones de IMAP
     * @param folder Carpeta en caso que se quira usar una diferente a la configuración de la conexión
     * @return Dirección completa para acceder al Mailbox en IMAP
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2021-07-20
     */
    private function createMailbox($folder = null)
    {
        $default_folder = !empty($this->config['folder']) ? $this->config['folder'] : 'INBOX';
        // si el mailbox no está asignado en la configuración se asigna con estándar INBOX como carpeta
        if (empty($this->config['mailbox'])) {
            $options = ['imap'];
            if ($this->config['ssl']) {
                $options[] = 'ssl';
                if (!$this->config['sslcheck']) {
                    $options[] = 'novalidate-cert';
                }
            }
            $this->config['mailbox'] = '{'.$this->config['host'].':'.$this->config['port'].'/'.implode('/',$options).'}'.$default_folder;
        }
        // se separa la carpeta del mailbox y se agrega la carpeta real que se busca
        $aux = explode('}', $this->config['mailbox']);
        if ($folder === null) {
            $folder = !empty($aux[1]) ? $aux[1] : $default_folder;
        }
        return $aux[0].'}'.$folder;
    }

    /**
     * Método que indica si se está o no conectado al servidor IMAP
     * @return =true si se está conectado
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function isConnected()
    {
        return (boolean)$this->link;
    }

    /**
     * Método que comprueba la casilla de correo
     * @return Arreglo con los datos de la casilla de correo
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function check()
    {
        return (array)imap_check($this->link);
    }

    /**
     * Método que entrega la cantidad de mensajes de la casilla de correo
     * @return Cantidad de mensajes en la casilla (leídos y no leídos)
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-01-05
     */
    public function countMessages()
    {
        return imap_num_msg($this->link);
    }

    /**
     * Método que entrega la cantidad de mensajes sin leer de la casilla de correo
     * @return Cantidad de mensajes sin leer
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2021-08-02
     */
    public function countUnreadMessages($folder = null)
    {
        $status = $this->status($folder);
        if (isset($status['unseen'])) {
            return (int)$status['unseen'];
        }
        if ($folder !== null) {
            throw new \Exception('No fue posible obtener la cantidad de correos sin leer al especificar la carpeta '.$folder);
        }
        return count($this->search('UNSEEN'));
    }

    /**
     * Método que entrega la información de estado de una casilla de correo
     * @return Arreglo con el estado de la casilla de correo
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2021-08-02
     */
    public function status($folder = null)
    {
        return (array)imap_status($this->link, $this->createMailbox($folder), SA_ALL);
    }

    /**
     * Método que realiza una búsqueda sobre los mensajes de la casilla de correo
     * @param filter Criterios de búsqueda para la casilla
     * @return Arreglo con UIDs de los mensajes que coincidían con el filtro
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2015-03-14
     */
    public function search($filter = 'UNSEEN')
    {
        $uids = imap_search($this->link, $filter, SE_UID);
        return $uids===false ? [] : $uids;
    }

    /**
     * Método que entrega el número de mensaje a partir del UID
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2017-04-07
     */
    public function getMsgNumber($uid)
    {
        return imap_msgno($this->link, $uid);
    }

    /**
     * Método que entrega la información de la cabecera del mensaje
     * @author <NAME>, DeLaF (esteban[at]delaf.cl)
     * @version 2017-04-07
     */
    public function getHeaderInfo($uid)
{'fraction_non_alphanumeric': 0.13364847443059732, 'fraction_numerical': 0.015184071049992838, 'mean_word_length': 2.3017261764010404, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 108, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1873109', 'n_tokens_mistral': 4700, 'n_tokens_neox': 4517, 'n_words': 1270}