session->remove('folders'); $rc->session->remove('unseen_count'); if ($identId == -1) { // Switch to main account ident_switch::write_log('Switching mailbox back to default.'); // Restore everything with STORAGE*my_postfix foreach ($_SESSION as $k => $v) { if (str_starts_with(strtolower($k), 'storage') && str_ends_with($k, ident_switch::MY_POSTFIX)) { $realKey = substr($k, 0, -$my_postfix_len); $_SESSION[$realKey] = $_SESSION[$k]; $rc->session->remove($k); } } $_SESSION['imap_delimiter'] = $_SESSION['imap_delimiter' . ident_switch::MY_POSTFIX] ?? '.'; $_SESSION['username'] = $rc->user->data['username']; $_SESSION['password'] = $_SESSION['password' . ident_switch::MY_POSTFIX]; $_SESSION['iid' . ident_switch::MY_POSTFIX] = -1; foreach (rcube_storage::$folder_types as $type) { $otherKey = $type . '_mbox' . ident_switch::MY_POSTFIX; if (isset($_SESSION[$otherKey])) { $rc->session->remove($otherKey); } } } else { $sql = 'SELECT imap_host, flags, imap_port, imap_delimiter, drafts_mbox, sent_mbox, junk_mbox, trash_mbox, username, password, iid FROM ' . $rc->db->table_name(ident_switch::TABLE) . ' WHERE id = ? AND user_id = ?'; $q = $rc->db->query($sql, $identId, $rc->user->ID); $r = $rc->db->fetch_assoc($q); if (is_array($r)) { if (!$r['username']) { // Load email from identity $sql = 'SELECT email FROM ' . $rc->db->table_name('identities') . ' WHERE identity_id = ?'; $q = $rc->db->query($sql, $r['iid']); $rIid = $rc->db->fetch_assoc($q); $r['username'] = $rIid['email']; } ident_switch::write_log("Switching mailbox to one for identity with ID = {$r['iid']} (username = '{$r['username']}')."); if ($_SESSION['username'] === $rc->user->data['username']) { // If we are in default account now - save values foreach ($_SESSION as $k => $v) { if (str_starts_with(strtolower($k), 'storage') && !str_ends_with($k, ident_switch::MY_POSTFIX)) { if (!isset($_SESSION[$k . ident_switch::MY_POSTFIX])) { $_SESSION[$k . ident_switch::MY_POSTFIX] = $_SESSION[$k]; } $rc->session->remove($k); } } foreach (['password', 'imap_delimiter'] as $k) { if (!isset($_SESSION[$k . ident_switch::MY_POSTFIX])) { $_SESSION[$k . ident_switch::MY_POSTFIX] = $_SESSION[$k]; } $rc->session->remove($k); } } $def_port = 143; $ssl = null; if ($r['flags'] & ident_switch::DB_SECURE_IMAP_TLS) { $ssl = 'tls'; } $port = $r['imap_port'] ?: $def_port; $host = $r['imap_host'] ?: 'localhost'; if ($ssl && !str_starts_with(strtolower($host), "{$ssl}://")) { $host = "{$ssl}://" . $host; } $delimiter = $r['imap_delimiter'] ?: '.'; $_SESSION['storage_host'] = $host; $_SESSION['storage_ssl'] = $ssl; $_SESSION['storage_port'] = $port; $_SESSION['imap_delimiter'] = $delimiter; $_SESSION['username'] = $r['username']; $_SESSION['password'] = $r['password']; $_SESSION['iid' . ident_switch::MY_POSTFIX] = $r['iid']; foreach (rcube_storage::$folder_types as $type) { if (!empty($r[$type . '_mbox'])) { $otherKey = $type . '_mbox' . ident_switch::MY_POSTFIX; $_SESSION[$otherKey] = $r[$type . '_mbox']; } } } else { ident_switch::write_log("Requested remote mailbox with ID = {$identId} not found."); return; } } $rc->output->redirect([ '_task' => 'mail', '_mbox' => 'INBOX', ]); } /** * Handle smtp_connect hook: configure SMTP settings for the active account. * * Loads SMTP host, port, credentials, and TLS settings from the database * for the currently selected identity. * * @param array $args Hook arguments containing SMTP connection parameters. * @return array Modified hook arguments with updated SMTP settings. */ public function configure_smtp(array $args): array { $iid = $_SESSION['iid' . ident_switch::MY_POSTFIX] ?? null; if (!is_numeric($iid) || $iid == -1) { ident_switch::write_log('no identity switch is selected... trying to find related smtp server from the from header'); $requestFrom = rcube_utils::get_input_value('_from', rcube_utils::INPUT_POST); if (empty($requestFrom)) { ident_switch::write_log('no _from post parameter found... falling back to original default config'); return $args; } $iid = intval($requestFrom); if ($iid === 0) { ident_switch::write_log('falling back to original default config as _from post field is no integer: ' . $_POST['_from']); return $args; } } $rc = rcmail::get_instance(); $sql = 'SELECT smtp_host, flags, smtp_port, username, smtp_auth, password FROM ' . $rc->db->table_name(ident_switch::TABLE) . ' WHERE iid = ? AND user_id = ?'; $q = $rc->db->query($sql, $iid, $rc->user->ID); $r = $rc->db->fetch_assoc($q); if (is_array($r)) { if (!$r['username']) { // Load email from identity $sql = 'SELECT email FROM ' . $rc->db->table_name('identities') . ' WHERE identity_id = ?'; $q = $rc->db->query($sql, $iid); $rIid = $rc->db->fetch_assoc($q); $r['username'] = $rIid['email']; } $args['smtp_user'] = $r['username']; $args['smtp_pass'] = $r['smtp_auth'] == ident_switch::SMTP_AUTH_IMAP ? $rc->decrypt($r['password']) : ''; // In RC 1.6+ smtp_server was renamed to smtp_host and includes port $smtpHost = $r['smtp_host'] ?: 'localhost'; if ($r['flags'] & ident_switch::DB_SECURE_IMAP_TLS) { if (str_contains($smtpHost, ':')) { ident_switch::write_log('SMTP server already contains protocol, ignoring TLS flag.'); } else { $smtpHost = 'tls://' . $smtpHost; } } $smtpPort = $r['smtp_port'] ?: 587; $args['smtp_host'] = $smtpHost . ':' . $smtpPort; } return $args; } /** * Handle preferences_list hook: customize special folders form for remote accounts. * * When viewing folder preferences while impersonating, shows the remote account's * special folder assignments instead of the default ones. * * @param array $args Hook arguments containing 'section' and 'blocks' with form data. * @return array Modified hook arguments with updated folder selections. */ public function get_special_folders_form(array $args): array { $rc = rcmail::get_instance(); if ($args['section'] === 'folders' && strcasecmp($rc->user->data['username'], $_SESSION['username']) !== 0 ) { $no_override = array_flip((array)$rc->config->get('dont_override')); $onchange = "if ($(this).val() == 'INBOX') $(this).val('')"; $select = $rc->folder_selector([ 'noselection' => '---', 'realnames' => true, 'maxlength' => 30, 'folder_filter' => 'mail', 'folder_rights' => 'w', ]); $sql = 'SELECT label FROM ' . $rc->db->table_name(ident_switch::TABLE) . ' WHERE iid = ? AND user_id = ?'; $q = $rc->db->query($sql, $_SESSION['iid' . ident_switch::MY_POSTFIX], $rc->user->ID); $r = $rc->db->fetch_assoc($q); $args['blocks']['main']['name'] .= ' (' . ($r['label'] ? rcube::Q($rc->gettext('server')) . ': ' . $r['label'] : 'remote') . ')'; foreach (rcube_storage::$folder_types as $type) { if (isset($no_override[$type . '_mbox'])) { continue; } $defaultKey = $type . '_mbox_default' . ident_switch::MY_POSTFIX; $otherKey = $type . '_mbox' . ident_switch::MY_POSTFIX; $selected = $_SESSION[$otherKey] ?? $_SESSION[$defaultKey] ?? ''; $attr = ['id' => '_' . $type . '_mbox', 'name' => '_' . $type . '_mbox', 'onchange' => $onchange]; $args['blocks']['main']['options'][$type . '_mbox']['content'] = $select->show($selected, $attr); } } return $args; } /** * Handle preferences_save hook: persist special folder assignments for remote accounts. * * Saves folder preferences to the plugin's database table instead of the default * Roundcube preferences when impersonating a remote account. * * @param array $args Hook arguments containing 'section' and 'prefs' with folder data. * @return array Modified hook arguments, with 'abort' set to prevent default save. */ public function save_special_folders(array $args): array { $rc = rcmail::get_instance(); if ($args['section'] === 'folders' && strcasecmp($rc->user->data['username'], $_SESSION['username']) !== 0 ) { $sql = 'SELECT id FROM ' . $rc->db->table_name(ident_switch::TABLE) . ' WHERE iid = ? AND user_id = ?'; $q = $rc->db->query($sql, $_SESSION['iid' . ident_switch::MY_POSTFIX], $rc->user->ID); $r = $rc->db->fetch_assoc($q); if ($r) { $sql = 'UPDATE ' . $rc->db->table_name(ident_switch::TABLE) . ' SET drafts_mbox = ?, sent_mbox = ?, junk_mbox = ?, trash_mbox = ?' . ' WHERE id = ?'; $rc->db->query( $sql, $args['prefs']['drafts_mbox'], $args['prefs']['sent_mbox'], $args['prefs']['junk_mbox'], $args['prefs']['trash_mbox'], $r['id'] ); // Abort to prevent RC from saving prefs to default storage $args['abort'] = true; $args['result'] = true; foreach (rcube_storage::$folder_types as $type) { if (!empty($args['prefs'][$type . '_mbox'])) { $otherKey = $type . '_mbox' . ident_switch::MY_POSTFIX; $_SESSION[$otherKey] = $args['prefs'][$type . '_mbox']; } } return $args; } $args['abort'] = true; $args['result'] = false; return $args; } foreach (rcube_storage::$folder_types as $type) { if (!empty($args['prefs'][$type . '_mbox'])) { $key = $type . '_mbox_default' . ident_switch::MY_POSTFIX; $_SESSION[$key] = $args['prefs'][$type . '_mbox']; } } return $args; } }