<?php

/**
 * Copy a new users identities and contacts from a nearby Squirrelmail installation
 *
 * @version 1.6
 *
 * @author Thomas Bruederli, Johannes Hessellund, pommi, Thomas Lueder
 */
class squirrelmail_usercopy extends rcube_plugin
{
    public $task = 'login';

    private $prefs;
    private $identities_level = 0;
    private $abook = [];

    #[\Override]
    public function init()
    {
        $this->add_hook('user_create', [$this, 'create_user']);
        $this->add_hook('identity_create', [$this, 'create_identity']);
    }

    public function create_user($p)
    {
        $rcmail = rcmail::get_instance();

        // Read plugin's config
        $this->initialize();

        // read prefs and add email address
        $this->read_squirrel_prefs($p['user']);

        if (
            ($this->identities_level == 0 || $this->identities_level == 2)
            && $rcmail->config->get('squirrelmail_set_alias')
            && !empty($this->prefs['email_address'])
        ) {
            $p['user_email'] = $this->prefs['email_address'];
        }

        return $p;
    }

    public function create_identity($p)
    {
        $rcmail = rcmail::get_instance();

        // prefs are set in create_user()
        if ($this->prefs) {
            if (!empty($this->prefs['full_name'])) {
                $p['record']['name'] = $this->prefs['full_name'];
            }

            if (
                ($this->identities_level == 0 || $this->identities_level == 2)
                && !empty($this->prefs['email_address'])
            ) {
                $p['record']['email'] = $this->prefs['email_address'];
            }

            if (!empty($this->prefs['___signature___'])) {
                $p['record']['signature'] = $this->prefs['___signature___'];
            }

            if (!empty($this->prefs['reply_to'])) {
                $p['record']['reply-to'] = $this->prefs['reply_to'];
            }

            if (
                ($this->identities_level == 0 || $this->identities_level == 1)
                && isset($this->prefs['identities']) && $this->prefs['identities'] > 1
            ) {
                for ($i = 1; $i < $this->prefs['identities']; $i++) {
                    unset($ident_data);
                    $ident_data = ['name' => '', 'email' => '']; // required data

                    if (!empty($this->prefs['full_name' . $i])) {
                        $ident_data['name'] = $this->prefs['full_name' . $i];
                    }

                    if ($this->identities_level == 0 && !empty($this->prefs['email_address' . $i])) {
                        $ident_data['email'] = $this->prefs['email_address' . $i];
                    } else {
                        $ident_data['email'] = $p['record']['email'];
                    }

                    if (!empty($this->prefs['reply_to' . $i])) {
                        $ident_data['reply-to'] = $this->prefs['reply_to' . $i];
                    }

                    if (!empty($this->prefs['___sig' . $i . '___'])) {
                        $ident_data['signature'] = $this->prefs['___sig' . $i . '___'];
                    }

                    // insert identity
                    $rcmail->user->insert_identity($ident_data);
                }
            }

            // copy address book
            $contacts = $rcmail->get_address_book(null, true);
            $addresses = [];
            $groups = [];

            if ($contacts && !empty($this->abook)) {
                foreach ($this->abook as $rec) {
                    // #1487096: handle multi-address and/or too long items
                    // #1487858: convert multi-address contacts into groups
                    $emails = preg_split('/[;,]/', $rec['email'], -1, \PREG_SPLIT_NO_EMPTY);
                    $group_id = null;

                    // create group for addresses
                    if (count($emails) > 1) {
                        if (!empty($groups[$rec['name']])) {
                            $group_id = $groups[$rec['name']];
                        } elseif ($group = $contacts->create_group($rec['name'])) {
                            $group_id = $group['id'];
                            $groups[$rec['name']] = $group_id;
                        }
                    }

                    // create contacts
                    foreach ($emails as $email) {
                        $contact_id = null;

                        if (!empty($addresses[$email])) {
                            $contact_id = $addresses[$email];
                        } elseif (rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) {
                            $rec['email'] = rcube_utils::idn_to_utf8($email);
                            if ($contact_id = $contacts->insert($rec, true)) {
                                $addresses[$email] = $contact_id;
                            }
                        }

                        if (!empty($group_id) && !empty($contact_id)) {
                            $contacts->add_to_group($group_id, [$contact_id]);
                        }
                    }
                }
            }

            // mark identity as complete for following hooks
            $p['complete'] = true;
        }

        return $p;
    }

    private function initialize()
    {
        $rcmail = rcmail::get_instance();

        // Load plugin's config file
        $this->load_config();

        // Set identities_level for operations of this plugin
        $ilevel = $rcmail->config->get('squirrelmail_identities_level');
        if ($ilevel === null) {
            $ilevel = $rcmail->config->get('identities_level', 0);
        }

        $this->identities_level = intval($ilevel);
    }

    private function read_squirrel_prefs($uname)
    {
        $rcmail = rcmail::get_instance();

        // File based backend
        if ($rcmail->config->get('squirrelmail_driver') == 'file' && ($srcdir = $rcmail->config->get('squirrelmail_data_dir'))) {
            if (($hash_level = $rcmail->config->get('squirrelmail_data_dir_hash_level')) > 0) {
                $srcdir = slashify($srcdir) . chunk_split(substr(base_convert(crc32($uname), 10, 16), 0, $hash_level), 1, '/');
            }
            $file_charset = $rcmail->config->get('squirrelmail_file_charset');
            $prefsfile = slashify($srcdir) . $uname . '.pref';
            $abookfile = slashify($srcdir) . $uname . '.abook';
            $sigfile = slashify($srcdir) . $uname . '.sig';
            $sigbase = slashify($srcdir) . $uname . '.si';

            if (is_readable($prefsfile)) {
                $this->prefs = [];
                foreach (file($prefsfile) as $line) {
                    [$key, $value] = rcube_utils::explode('=', $line);
                    $this->prefs[$key] = $this->convert_charset(rtrim($value), $file_charset);
                }

                // also read signature file if exists
                if (is_readable($sigfile)) {
                    $sig = file_get_contents($sigfile);
                    $this->prefs['___signature___'] = $this->convert_charset($sig, $file_charset);
                }

                if (isset($this->prefs['identities']) && $this->prefs['identities'] > 1) {
                    for ($i = 1; $i < $this->prefs['identities']; $i++) {
                        // read signature file if exists
                        if (is_readable($sigbase . $i)) {
                            $sig = file_get_contents($sigbase . $i);
                            $this->prefs['___sig' . $i . '___'] = $this->convert_charset($sig, $file_charset);
                        }
                    }
                }

                // parse address book file
                if (filesize($abookfile)) {
                    foreach (file($abookfile) as $line) {
                        $line = $this->convert_charset(rtrim($line), $file_charset);
                        $line = str_getcsv($line, '|');

                        $rec = [
                            'name' => $line[0],
                            'firstname' => $line[1],
                            'surname' => $line[2],
                            'email' => $line[3],
                            'notes' => $line[4],
                        ];

                        if ($rec['name'] && $rec['email']) {
                            $this->abook[] = $rec;
                        }
                    }
                }
            }
        }
        // Database backend
        elseif ($rcmail->config->get('squirrelmail_driver') == 'sql') {
            $this->prefs = [];

            // connect to squirrelmail database
            $db = rcube_db::factory($rcmail->config->get('squirrelmail_dsn'));

            $db->set_debug($rcmail->config->get('sql_debug'));
            $db->db_connect('r'); // connect in read mode

            // retrieve prefs
            $userprefs_table = $rcmail->config->get('squirrelmail_userprefs_table');
            $address_table = $rcmail->config->get('squirrelmail_address_table');
            $db_charset = $rcmail->config->get('squirrelmail_db_charset');

            if ($db_charset) {
                $db->query('SET NAMES ' . $db_charset);
            }

            $sql_result = $db->query('SELECT * FROM ' . $db->quote_identifier($userprefs_table)
                . ' WHERE `user` = ?', $uname); // ? is replaced with emailaddress

            while ($sql_array = $db->fetch_assoc($sql_result)) { // fetch one row from result
                $this->prefs[$sql_array['prefkey']] = rcube_charset::convert(rtrim($sql_array['prefval']), $db_charset);
            }

            // retrieve address table data
            $sql_result = $db->query('SELECT * FROM ' . $db->quote_identifier($address_table)
                . ' WHERE `owner` = ?', $uname); // ? is replaced with emailaddress

            // parse address book
            // fetch one row from result
            while ($sql_array = $db->fetch_assoc($sql_result)) {
                $rec = [
                    'name' => rcube_charset::convert(rtrim($sql_array['nickname']), $db_charset),
                    'firstname' => rcube_charset::convert(rtrim($sql_array['firstname']), $db_charset),
                    'surname' => rcube_charset::convert(rtrim($sql_array['lastname']), $db_charset),
                    'email' => rcube_charset::convert(rtrim($sql_array['email']), $db_charset),
                    'notes' => rcube_charset::convert(rtrim($sql_array['label']), $db_charset),
                ];

                if ($rec['name'] && $rec['email']) {
                    $this->abook[] = $rec;
                }
            }
        } // end if 'sql'-driver
    }

    private function convert_charset($str, $charset = null)
    {
        if (!$charset) {
            return rcube_charset::clean($str);
        }

        return rcube_charset::convert($str, $charset, RCUBE_CHARSET);
    }
}
