Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24a9584d6f | ||
|
|
bcea012af0 | ||
|
|
a437a107ba | ||
|
|
8b2798e412 | ||
|
|
c28305509f | ||
|
|
8a8bca1ae5 | ||
|
|
28d7841af5 | ||
|
|
707abf2a81 | ||
|
|
c90efaa00b | ||
|
|
e4aeef2e07 | ||
|
|
e19b33a842 | ||
|
|
d540de77ff | ||
|
|
913065548b | ||
|
|
683b02027b | ||
|
|
7111e9e759 | ||
|
|
f5f3fbdf90 | ||
|
|
fcdff0ccc7 | ||
|
|
0e0b00dea2 | ||
|
|
c76942a6cd | ||
|
|
17044fe501 | ||
|
|
f644b80c0e | ||
|
|
dd2d8e10a4 | ||
|
|
8ca4d3bf56 | ||
|
|
829615ec5d | ||
|
|
6285d0bffd | ||
|
|
a3ccfb5a8f | ||
|
|
08f6c86773 | ||
|
|
8b527820e9 | ||
|
|
b3adf0842f | ||
|
|
deac908a77 | ||
|
|
f1874e3fe7 | ||
|
|
5096826621 | ||
|
|
7a97816d1c | ||
|
|
6849c47fd9 | ||
|
|
ecbadcd866 | ||
|
|
9ebacf0d61 | ||
|
|
ab7bae56b5 | ||
|
|
d93dd2be03 | ||
|
|
f7b650db3e | ||
|
|
4da9b48776 | ||
|
|
d667518d1f | ||
|
|
5ad75ce989 | ||
|
|
dbadde3333 | ||
|
|
b499688318 | ||
|
|
6cfbeab7f0 | ||
|
|
b10f3625c2 | ||
|
|
f28fb5bb58 | ||
|
|
1b424b4348 | ||
|
|
6705312240 | ||
|
|
05ea494fa6 | ||
|
|
5a704f2717 | ||
|
|
01edffa66b | ||
|
|
9367409f36 | ||
|
|
bbf28eed57 | ||
|
|
ec71910156 | ||
|
|
f700593730 | ||
|
|
9db4f48593 | ||
|
|
2b9c43858e | ||
|
|
95716183d7 | ||
|
|
40e7f5664e | ||
|
|
ea62869891 | ||
|
|
057c88ebc5 | ||
|
|
41186b613e | ||
|
|
3e41e57888 | ||
|
|
0925fca08a | ||
|
|
67dc78a48c | ||
|
|
1b7d90a92b |
19
README.md
19
README.md
@@ -1,2 +1,21 @@
|
||||
# ident_switch
|
||||
ident_switch plugin for Roundcube
|
||||
|
||||
This plugin allows users to switch between different accounts (including remote) in single Roundcube session.
|
||||
|
||||
*Inspired by identities_imap plugin that is no longer supported.*
|
||||
|
||||
### Where to start ###
|
||||
* In settigs interface create new identity.
|
||||
* For all identities except default you will see new section of settings - IMAP. Enter data required to connect to remote server. Don't forget to check Enabled check box.
|
||||
* After you have created at least one identity with active IMAP settings you will see combobox in the top right corner instead of plain text field with account name. It will allows you to switch to another account.
|
||||
|
||||
### Version compatibility ###
|
||||
* Branch 1.X - for Roundcube v1.1
|
||||
* Branch 2.X - for Roundcube v1.2
|
||||
* Branch 3.X - for Roundcube v1.3
|
||||
|
||||
Please specify verion like "~2.0" in your composer.json file for ident_switch requirement. In this case you will stay inside compatible branch until you manually update ypur Roundcube installation.
|
||||
|
||||
### Switching SMTP ###
|
||||
Plugin also switched SMTP credentials but only for server specified in general config. You should use %u and %p substitutions for user and password to make it work. This substitutions are replaced by username and password for selected IMAP account.
|
||||
|
||||
37
SQL/mysql.initial.sql
Normal file
37
SQL/mysql.initial.sql
Normal file
@@ -0,0 +1,37 @@
|
||||
CREATE TABLE IF NOT EXISTS ident_switch
|
||||
(
|
||||
id
|
||||
int(10) UNSIGNED
|
||||
NOT NULL
|
||||
AUTO_INCREMENT,
|
||||
user_id
|
||||
int(10) UNSIGNED
|
||||
NOT NULL,
|
||||
iid
|
||||
int(10) UNSIGNED
|
||||
NOT NULL,
|
||||
username
|
||||
varchar(64),
|
||||
password
|
||||
varchar(64),
|
||||
host
|
||||
varchar(64),
|
||||
port
|
||||
int
|
||||
CHECK(port > 0 AND port <= 65535),
|
||||
delimiter
|
||||
char(1),
|
||||
label
|
||||
varchar(32),
|
||||
flags
|
||||
int
|
||||
NOT NULL
|
||||
DEFAULT 0,
|
||||
UNIQUE KEY user_id_label (user_id, label),
|
||||
CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT fk_identity_id FOREIGN KEY (iid) REFERENCES identities(identity_id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
PRIMARY KEY(id),
|
||||
INDEX IX_ident_switch_user_id (user_id),
|
||||
INDEX IX_ident_switch_iid (iid)
|
||||
);
|
||||
|
||||
5
SQL/mysql/2016060200.sql
Normal file
5
SQL/mysql/2016060200.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
MODIFY
|
||||
username
|
||||
varchar(64);
|
||||
6
SQL/mysql/2018071600.sql
Normal file
6
SQL/mysql/2018071600.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
MODIFY
|
||||
username
|
||||
varchar(64)
|
||||
NULL;
|
||||
@@ -13,21 +13,18 @@ CREATE TABLE ident_switch
|
||||
REFERENCES identities(identity_id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
UNIQUE,
|
||||
username
|
||||
varchar(64)
|
||||
NOT NULL,
|
||||
varchar(64),
|
||||
password
|
||||
varchar(64),
|
||||
host
|
||||
varchar(64)
|
||||
NOT NULL,
|
||||
varchar(64),
|
||||
port
|
||||
integer
|
||||
CHECK(port > 0 AND port <= 65535),
|
||||
delimiter
|
||||
char(1),
|
||||
label
|
||||
varchar(32)
|
||||
NOT NULL,
|
||||
varchar(32),
|
||||
flags
|
||||
integer
|
||||
NOT NULL
|
||||
11
SQL/postgres/2016052000.sql
Normal file
11
SQL/postgres/2016052000.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
ALTER COLUMN
|
||||
host
|
||||
DROP NOT NULL;
|
||||
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
ALTER COLUMN
|
||||
label
|
||||
DROP NOT NULL;
|
||||
5
SQL/postgres/2016060200.sql
Normal file
5
SQL/postgres/2016060200.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
ALTER COLUMN
|
||||
username
|
||||
DROP NOT NULL;
|
||||
5
SQL/postgres/2018081600.sql
Normal file
5
SQL/postgres/2018081600.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE
|
||||
ident_switch
|
||||
ALTER COLUMN
|
||||
username
|
||||
DROP NOT NULL;
|
||||
@@ -22,12 +22,15 @@
|
||||
"php": ">=5.3.0",
|
||||
"roundcube/plugin-installer": ">=0.1.3"
|
||||
},
|
||||
"conflict": {
|
||||
"elm/identity_smtp": "*"
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://bitbucket.org/BoresExpress/ident_switch/issues"
|
||||
},
|
||||
"extra": {
|
||||
"roundcube": {
|
||||
"min-version": "1.1",
|
||||
"min-version": "1.3",
|
||||
"sql-dir": "SQL"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
/* Password encryption:
|
||||
'rcmail': encrypt passwords by default Roundcube methods.
|
||||
'secure': encrypt passwords by using the IMAP password as encryption key.
|
||||
NOTE: When using 'secure' encryption, If IMAP passwords are changed
|
||||
using methods other than Roundcube Webmail interface
|
||||
(hmail_password or password plugin) then IMAP server identities
|
||||
passwords must be re-entered by users.
|
||||
*/
|
||||
$rcmail_config['identities_imap_crypt'] = 'rcmail';
|
||||
|
||||
/* password encryption salt (only used for secure encryption) */
|
||||
$rcmail_config['identities_imap_salt'] = '!kQm*fF3pXe1Kbm%9';
|
||||
|
||||
/* predefined imap hosts (associated with the domain part of the identity email property) */
|
||||
$rcmail_config['identities_imap_external'] = array(
|
||||
);
|
||||
|
||||
$rcmail_config['identities_imap_internal'] = array(
|
||||
'BoresSoft Webmail' => array(
|
||||
'host' =>'localhost',
|
||||
'delimiter' => '/',
|
||||
'readonly' => false, // on match prevent field editing
|
||||
),
|
||||
);
|
||||
?>
|
||||
@@ -1,44 +1,29 @@
|
||||
<?php
|
||||
/* Password encryption:
|
||||
'rcmail': encrypt passwords by default Roundcube methods.
|
||||
'secure': encrypt passwords by using the IMAP password as encryption key.
|
||||
NOTE: When using 'secure' encryption, If IMAP passwords are changed
|
||||
using methods other than Roundcube Webmail interface
|
||||
(hmail_password or password plugin) then IMAP server identities
|
||||
passwords must be re-entered by users.
|
||||
*/
|
||||
$rcmail_config['identities_imap_crypt'] = 'rcmail';
|
||||
|
||||
/* password encryption salt (only used for secure encryption) */
|
||||
$rcmail_config['identities_imap_salt'] = '!kQm*fF3pXe1Kbm%9';
|
||||
|
||||
/* predefined imap hosts (associated with the domain part of the identity email property) */
|
||||
$rcmail_config['identities_imap_external'] = array(
|
||||
'gmail.com' => array(
|
||||
'host' =>'ssl://imap.gmail.com:993',
|
||||
'delimiter' => '/',
|
||||
'readonly' => true, // on match prevent field editing
|
||||
),
|
||||
'googlemail.com' => array(
|
||||
'host' =>'ssl://imap.gmail.com:993',
|
||||
'delimiter' => '/',
|
||||
'readonly' => true, // on match prevent field editing
|
||||
),
|
||||
'freenet.de' => array(
|
||||
'host' =>'mx.freenet.de',
|
||||
'delimiter' => '.',
|
||||
'readonly' => false, // on match prevent field editing
|
||||
),
|
||||
);
|
||||
|
||||
$rcmail_config['identities_imap_internal'] = array(
|
||||
'mydomain.tld' => array(
|
||||
'host' =>'ssl://imap.mydomain.tld:993',
|
||||
'delimiter' => '/',
|
||||
'readonly' => true, // on match prevent field editing
|
||||
),
|
||||
);
|
||||
|
||||
/* auto-detect IMAP server */
|
||||
$rcmail_config['identities_imap_autodetect'] = false;
|
||||
?>
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Preconfigured settings for different mail domains.
|
||||
* Appropriate set of values is searched by mapping domain of email (from identity) to array key.
|
||||
*/
|
||||
$rcmail_config['ident_switch.preconfig'] = array(
|
||||
|
||||
# Domain part of email address
|
||||
'domain.tld' => array(
|
||||
|
||||
# Hostname, use ssl:// or tls:// notation if needed, for no security use imap:// (must always start with scheme).
|
||||
# Required.
|
||||
'host' => 'imap://mail.domain.tld',
|
||||
|
||||
# Login name, can be 'email' (full address from identity), 'mbox' (only mailbox part).
|
||||
# Any other value is threated ad 'not specified' (default).
|
||||
'user' => 'email',
|
||||
|
||||
# Are specified settings locked in interface or not.
|
||||
# Default - false.
|
||||
'readonly' => true
|
||||
),
|
||||
|
||||
'another.tld' => array(
|
||||
'host' => 'tls://mail.another.tld',
|
||||
'user' => 'mbox',
|
||||
),
|
||||
);
|
||||
|
||||
10
ident_switch-form.js
Normal file
10
ident_switch-form.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* This is part of identity_imap plugin
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
$("INPUT[name='_ident_switch.form.enabled']").change();
|
||||
$("SELECT[name='_ident_switch.form.secure']").change();
|
||||
plugin_switchIdent_processPreconfig();
|
||||
});
|
||||
|
||||
1
ident_switch-form.min.js
vendored
Normal file
1
ident_switch-form.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
$(function(){$("INPUT[name='_ident_switch.form.enabled']").change();$("SELECT[name='_ident_switch.form.secure']").change();plugin_switchIdent_processPreconfig();});
|
||||
89
ident_switch-switch.js
Normal file
89
ident_switch-switch.js
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* This is part of identity_imap plugin
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
$sw = $('#plugin-ident_switch-account');
|
||||
isOk = false;
|
||||
|
||||
switch (rcmail.env['skin']) {
|
||||
case 'larry':
|
||||
isOk = plugin_switchIdent_addCbLarry($sw);
|
||||
break;
|
||||
case 'classic':
|
||||
isOk = plugin_switchIdent_addCbClassic($sw);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isOk)
|
||||
$sw.show();
|
||||
|
||||
$("INPUT[name='_ident_switch.form.enabled']").change();
|
||||
$("SELECT[name='_ident_switch.form.secure']").change();
|
||||
plugin_switchIdent_processPreconfig();
|
||||
});
|
||||
|
||||
function plugin_switchIdent_addCbLarry($sw) {
|
||||
var $truName = $('.topright .username');
|
||||
if ($truName.length > 0) {
|
||||
if ($sw.length > 0) {
|
||||
$sw.prependTo('.topright');
|
||||
$truName.hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function plugin_switchIdent_addCbClassic($sw) {
|
||||
var $taskBar = $('#taskbar');
|
||||
if ($taskBar.length > 0) {
|
||||
$taskBar.prepend($sw);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function plugin_switchIdent_processPreconfig() {
|
||||
var disFld = $("INPUT[name='_ident_switch.form.readonly']");
|
||||
disFld.parentsUntil("TABLE", "TR").hide();
|
||||
|
||||
var disVal = disFld.val();
|
||||
if (disVal > 0) {
|
||||
$("INPUT[name='_ident_switch.form.host']").prop("disabled", true);
|
||||
$("SELECT[name='_ident_switch.form.secure']").prop("disabled", true);
|
||||
$("INPUT[name='_ident_switch.form.port']").prop("disabled", true);
|
||||
}
|
||||
if (2 == disVal) {
|
||||
$("INPUT[name='_ident_switch.form.username']").prop("disabled", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function plugin_switchIdent_enabled_onChange(e) {
|
||||
var $enFld = $("INPUT[name='_ident_switch.form.enabled']");
|
||||
$("INPUT[name!='_ident_switch.form.enabled'], SELECT", $enFld.parents("FIELDSET")).prop("disabled", !$enFld.is(":checked"));
|
||||
plugin_switchIdent_processPreconfig();
|
||||
}
|
||||
|
||||
function plugin_switchIdent_secure_onChange(e) {
|
||||
var $secSel = $("SELECT[name='_ident_switch.form.secure']");
|
||||
var $portFld = $("INPUT[name='_ident_switch.form.port']");
|
||||
|
||||
if ('SSL' === $secSel.val().toUpperCase())
|
||||
$portFld.attr("placeholder", 993);
|
||||
else
|
||||
$portFld.attr("placeholder", 143);
|
||||
}
|
||||
|
||||
function plugin_switchIdent_switch(val) {
|
||||
rcmail.http_post('plugin.ident_switch.switch', { '_ident-id': val, '_mbox': rcmail.env.mailbox });
|
||||
}
|
||||
|
||||
function plugin_switchIdent_fixIdent(iid) {
|
||||
if (parseInt(iid) > 0)
|
||||
$("#_from").val(iid);
|
||||
}
|
||||
15
ident_switch-switch.min.js
vendored
Normal file
15
ident_switch-switch.min.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
$(function(){$sw=$('#plugin-ident_switch-account');isOk=false;switch(rcmail.env['skin']){case'larry':isOk=plugin_switchIdent_addCbLarry($sw);break;case'classic':isOk=plugin_switchIdent_addCbClassic($sw);break;}
|
||||
if(isOk)
|
||||
$sw.show();$("INPUT[name='_ident_switch.form.enabled']").change();$("SELECT[name='_ident_switch.form.secure']").change();plugin_switchIdent_processPreconfig();});function plugin_switchIdent_addCbLarry($sw){var $truName=$('.topright .username');if($truName.length>0){if($sw.length>0){$sw.prependTo('.topright');$truName.hide();return true;}}
|
||||
return false;}
|
||||
function plugin_switchIdent_addCbClassic($sw){var $taskBar=$('#taskbar');if($taskBar.length>0){$taskBar.prepend($sw);return true;}
|
||||
return false;}
|
||||
function plugin_switchIdent_processPreconfig(){var disFld=$("INPUT[name='_ident_switch.form.readonly']");disFld.parentsUntil("TABLE","TR").hide();var disVal=disFld.val();if(disVal>0){$("INPUT[name='_ident_switch.form.host']").prop("disabled",true);$("SELECT[name='_ident_switch.form.secure']").prop("disabled",true);$("INPUT[name='_ident_switch.form.port']").prop("disabled",true);}
|
||||
if(2==disVal){$("INPUT[name='_ident_switch.form.username']").prop("disabled",true);}}
|
||||
function plugin_switchIdent_enabled_onChange(e){var $enFld=$("INPUT[name='_ident_switch.form.enabled']");$("INPUT[name!='_ident_switch.form.enabled'], SELECT",$enFld.parents("FIELDSET")).prop("disabled",!$enFld.is(":checked"));plugin_switchIdent_processPreconfig();}
|
||||
function plugin_switchIdent_secure_onChange(e){var $secSel=$("SELECT[name='_ident_switch.form.secure']");var $portFld=$("INPUT[name='_ident_switch.form.port']");if('SSL'===$secSel.val().toUpperCase())
|
||||
$portFld.attr("placeholder",993);else
|
||||
$portFld.attr("placeholder",143);}
|
||||
function plugin_switchIdent_switch(val){rcmail.http_post('plugin.ident_switch.switch',{'_ident-id':val,'_mbox':rcmail.env.mailbox});}
|
||||
function plugin_switchIdent_fixIdent(iid){if(parseInt(iid)>0)
|
||||
$("#_from").val(iid);}
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* This is part of identity_imap plugin
|
||||
*/
|
||||
$(function() {
|
||||
if ($('#plugin-ident_switch-account').size() > 0) {
|
||||
$('#plugin-ident_switch-account').prependTo('.topright');
|
||||
$('.topright .username').hide();
|
||||
$('#plugin-ident_switch-account').show();
|
||||
}
|
||||
});
|
||||
|
||||
function plugin_switchIdent_switch(val) {
|
||||
console.log("qwe1");
|
||||
rcmail.http_post('plugin.ident_switch.switch', { '_ident-id': val });
|
||||
}
|
||||
581
ident_switch.php
581
ident_switch.php
@@ -12,20 +12,25 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
public $task='?(?!login|logout).*';
|
||||
|
||||
private $table = 'ident_switch';
|
||||
const TABLE = 'ident_switch';
|
||||
const MY_POSTFIX = '_iswitch';
|
||||
|
||||
// Flags user in database
|
||||
private $db_enabled = 1;
|
||||
private $db_secure = 2;
|
||||
const DB_ENABLED = 1;
|
||||
const DB_SECURE_SSL = 2;
|
||||
const DB_SECURE_TLS = 4;
|
||||
|
||||
function init()
|
||||
{
|
||||
$this->add_hook('startup', array($this, 'on_startup'));
|
||||
$this->add_hook('render_page', array($this, 'on_render_page'));
|
||||
# $this->add_hook('smtp_connect', array($this, 'on_smtp_connect'));
|
||||
$this->add_hook('smtp_connect', array($this, 'on_smtp_connect'));
|
||||
$this->add_hook('identity_form', array($this, 'on_identity_form'));
|
||||
$this->add_hook('identity_update', array($this, 'on_identity_update'));
|
||||
$this->add_hook('identity_create', array($this, 'on_identity_create'));
|
||||
$this->add_hook('identity_create_after', array($this, 'on_identity_create_after'));
|
||||
$this->add_hook('identity_delete', array($this, 'on_identity_delete'));
|
||||
$this->add_hook('template_object_composeheaders', array($this, 'on_template_object_composeheaders'));
|
||||
|
||||
$this->register_action('plugin.ident_switch.switch', array($this, 'on_switch'));
|
||||
}
|
||||
@@ -34,7 +39,7 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
if (strtolower($rc->user->data['username']) != strtolower($_SESSION['username']))
|
||||
if (strcasecmp($rc->user->data['username'], $_SESSION['username']) !== 0)
|
||||
{ // We are impersonating
|
||||
$rc->config->set('imap_cache', null);
|
||||
$rc->config->set('messages_cache', false);
|
||||
@@ -53,30 +58,74 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
switch ($rc->task)
|
||||
{
|
||||
case 'mail':
|
||||
$this->render_switch($rc, $args);
|
||||
case 'settings':
|
||||
$this->include_script('ident_switch-form.js');
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
private function render_switch($rc, $args)
|
||||
{
|
||||
// Currently selected identity
|
||||
$iid_s = $_SESSION['iid' . self::MY_POSTFIX];
|
||||
|
||||
$iid = 0;
|
||||
if (is_int($iid_s))
|
||||
$iid = $iid_s;
|
||||
elseif ($iid_s === '-1')
|
||||
$iid = -1;
|
||||
elseif (ctype_digit($iid_s))
|
||||
$iid = intval($iid_s);
|
||||
|
||||
// Get list of alternative accounts
|
||||
$sOpt = '';
|
||||
$sql = 'SELECT id, label, username FROM ' . $rc->db->table_name($this->table) . ' WHERE user_id = ? AND flags & ? > 0';
|
||||
$q = $rc->db->query($sql, $rc->user->data['user_id'], $this->db_enabled);
|
||||
while ($r = $rc->db->fetch_assoc($q))
|
||||
$sql = 'SELECT id, iid, label, username FROM ' . $rc->db->table_name(self::TABLE) . ' WHERE user_id = ? AND flags & ? > 0';
|
||||
$qRec = $rc->db->query($sql, $rc->user->data['user_id'], self::DB_ENABLED);
|
||||
while ($r = $rc->db->fetch_assoc($qRec))
|
||||
{
|
||||
$opts = array('value' => $r['id']);
|
||||
if (strcasecmp($_SESSION['username'], $r['username']) === 0)
|
||||
if ($iid == $r['iid'])
|
||||
$opts['selected'] = 'selected';
|
||||
|
||||
// Make label
|
||||
$lbl = $r['label'];
|
||||
if (!$lbl)
|
||||
{
|
||||
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'];
|
||||
}
|
||||
|
||||
if (strpos($r['username'], '@') === false)
|
||||
$lbl = $r['username'] . '@' . ($r['host'] ? $r['host'] : 'localhost');
|
||||
else
|
||||
$lbl = $r['username'];
|
||||
}
|
||||
|
||||
$sOpt .= html::tag(
|
||||
'option',
|
||||
$opts,
|
||||
$r['label']
|
||||
rcube::Q($lbl)
|
||||
);
|
||||
}
|
||||
|
||||
// Render UI if user has extra accounts
|
||||
if (!empty($sOpt))
|
||||
{
|
||||
|
||||
// Add main account
|
||||
$opts = array('value' => -1);
|
||||
if (strcasecmp($_SESSION['username'], $rc->user->data['username']) === 0)
|
||||
if ($iid <= 0)
|
||||
$opts['selected'] = 'selected';
|
||||
|
||||
$sOpt = html::tag(
|
||||
@@ -85,51 +134,64 @@ class ident_switch extends rcube_plugin
|
||||
$_SESSION['global_alias'] ? $_SESSION['global_alias'] : $rc->user->data['username']
|
||||
) . $sOpt;
|
||||
|
||||
$this->include_script('ident_switch.js');
|
||||
$this->include_script('ident_switch-switch.js');
|
||||
$sw = html::tag(
|
||||
'select',
|
||||
array(
|
||||
'id' => 'plugin-ident_switch-account',
|
||||
'style' => 'display: none;',
|
||||
'style' => 'display: none; padding: 0;',
|
||||
'onchange' => 'plugin_switchIdent_switch(this.value);',
|
||||
),
|
||||
$sOpt
|
||||
);
|
||||
$rc->output->add_footer($sw);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function on_smtp_connect($args)
|
||||
{
|
||||
error_log('on_smtp_connect');
|
||||
$iid = $_SESSION['iid' . self::MY_POSTFIX];
|
||||
if (!is_integer($iid) || $iid == -1)
|
||||
return $args;
|
||||
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
$sql = 'SELECT host, flags, port, username, password, iid FROM ' . $rc->db->table_name(self::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, $r['iid']);
|
||||
$rIid = $rc->db->fetch_assoc($q);
|
||||
|
||||
$r['username'] = $rIid['email'];
|
||||
}
|
||||
|
||||
// Exactly the same in core SMTP handler
|
||||
$args['smtp_user'] = str_replace('%u', $r['username'], $args['smtp_user']);
|
||||
$args['smtp_pass'] = str_replace('%p', $rc->decrypt($r['password']), $args['smtp_pass']);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function on_identity_form($args)
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
$this->add_texts('localization');
|
||||
|
||||
// Create our field set
|
||||
$args['form']['ident_switch'] = array(
|
||||
'name' => $this->gettext('form.caption'),
|
||||
'content' => array(
|
||||
'ident_switch.form.enabled' => array('type' => 'checkbox'),
|
||||
'ident_switch.form.label' => array('type' => 'text', 'size' => 32),
|
||||
'ident_switch.form.host' => array('type' => 'text', 'size' => 64),
|
||||
'ident_switch.form.secure' => array('type' => 'checkbox'),
|
||||
'ident_switch.form.port' => array('type' => 'text', 'size' => 5),
|
||||
'ident_switch.form.username' => array('type' => 'text', 'size' => 64),
|
||||
'ident_switch.form.password' => array('type' => 'password', 'size' => 64),
|
||||
'ident_switch.form.delimiter' => array('type' => 'text', 'size' => 1),
|
||||
),
|
||||
);
|
||||
// Do not show options for default identity
|
||||
if (strcasecmp($args['record']['email'], $rc->user->data['username']) === 0)
|
||||
return $args;
|
||||
|
||||
$this->add_texts('localization');
|
||||
|
||||
// Load data if exists
|
||||
if (isset($args['record']['identity_id']))
|
||||
{
|
||||
$sql = 'SELECT * FROM ' . $rc->db->table_name($this->table) . ' WHERE iid = ? AND user_id = ?';
|
||||
$sql = 'SELECT * FROM ' . $rc->db->table_name(self::TABLE) . ' WHERE iid = ? AND user_id = ?';
|
||||
$q = $rc->db->query($sql, $args['record']['identity_id'], $rc->user->ID);
|
||||
$r = $rc->db->fetch_assoc($q);
|
||||
if ($r)
|
||||
@@ -138,13 +200,72 @@ class ident_switch extends rcube_plugin
|
||||
$args['record']['ident_switch.form.' . $k] = $v;
|
||||
|
||||
// Parse flags
|
||||
if ($r['flags'] & $this->db_enabled)
|
||||
if ($r['flags'] & self::DB_ENABLED)
|
||||
$args['record']['ident_switch.form.enabled'] = true;
|
||||
if ($r['flags'] & $this->db_secure)
|
||||
$args['record']['ident_switch.form.secure'] = true;
|
||||
if ($r['flags'] & self::DB_SECURE_TLS) // TLS has priority
|
||||
$args['record']['ident_switch.form.secure'] = 'tls';
|
||||
elseif ($r['flags'] & self::DB_SECURE_SSL)
|
||||
$args['record']['ident_switch.form.secure'] = 'ssl';
|
||||
|
||||
// Set readonly if needed
|
||||
$cfg = $this->get_preconfig($args['record']['email']);
|
||||
if (is_array($cfg) && $cfg['readonly'])
|
||||
{
|
||||
$args['record']['ident_switch.form.readonly'] = 1;
|
||||
if (in_array(strtoupper($cfg['user']), array('EMAIL', 'MBOX')))
|
||||
$args['record']['ident_switch.form.readonly'] = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->apply_preconfig($args['record']);
|
||||
}
|
||||
|
||||
// Create our field set
|
||||
// Do that manually decause standard processing shows hidden fields (WTF?)
|
||||
$fieldset = array(
|
||||
'ident_switch.form.enabled' => array('type' => 'checkbox', 'onchange' => 'plugin_switchIdent_enabled_onChange();'),
|
||||
'ident_switch.form.label' => array('type' => 'text', 'size' => 32, 'placeholder' => $args['record']['email']),
|
||||
'ident_switch.form.host' => array('type' => 'text', 'size' => 64, 'placeholder' => 'localhost'),
|
||||
'ident_switch.form.secure' => array(
|
||||
'type' => 'select',
|
||||
'options' => array('ssl' => 'SSL', 'tls' => 'TLS'),
|
||||
'onchange' => 'plugin_switchIdent_secure_onChange();'
|
||||
),
|
||||
'ident_switch.form.port' => array('type' => 'text', 'size' => 5),
|
||||
'ident_switch.form.username' => array('type' => 'text', 'size' => 64, 'placeholder' => $args['record']['email']),
|
||||
'ident_switch.form.password' => array('type' => 'password', 'size' => 64),
|
||||
'ident_switch.form.delimiter' => array('type' => 'text', 'size' => 1, 'placeholder' => '.'),
|
||||
'ident_switch.form.readonly' => array('type' => 'hidden'),
|
||||
);
|
||||
|
||||
// Process fields
|
||||
$addAfter = '';
|
||||
$table = new html_table(array('cols' => 2));
|
||||
foreach ($fieldset as $col => $colprop)
|
||||
{
|
||||
$data = $args['record'][$col];
|
||||
if ($colprop['type'] == 'hidden')
|
||||
{
|
||||
$addAfter .= rcube_output::get_edit_field($col, $data, $colprop, $colprop['type']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$colprop['id'] = 'rcmfd_' . $col;
|
||||
|
||||
$label = $colprop['label'] ?: $this->gettext(str_replace('-', '', $col));
|
||||
$value = $colprop['value'] ?: rcube_output::get_edit_field($col, $data, $colprop, $colprop['type']);
|
||||
|
||||
$table->add('title', html::label($colprop['id'], rcube::Q($label)));
|
||||
$table->add(null, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// Set data for output
|
||||
$args['form']['ident_switch'] = array(
|
||||
'name' => $this->gettext('form.caption'),
|
||||
'content' => $table->show(array('class' => 'propform')) . $addAfter // TODO: copy styles from other tables
|
||||
);
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
@@ -152,43 +273,76 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
// TODO: check field values
|
||||
|
||||
$sql = 'SELECT NULL FROM ' . $rc->db->table_name($this->table) . ' WHERE iid = ? AND user_id = ?';
|
||||
$q = $rc->db->query($sql, $args['id'], $rc->user->ID);
|
||||
$r = $rc->db->fetch_assoc($q);
|
||||
if ($r)
|
||||
{ // Record already exists, will update it
|
||||
$sql = 'UPDATE ' .
|
||||
$rc->db->table_name($this->table) .
|
||||
' SET flags = ?, label = ?, host = ?, port = ?, username = ?, password = ?, delimiter = ?, user_id = ?, iid = ?';
|
||||
}
|
||||
else
|
||||
{ // No record exists, create new one
|
||||
$sql = 'INSERT INTO ' .
|
||||
$rc->db->table_name($this->table) .
|
||||
'(flags, label, host, port, username, password, delimiter, user_id, iid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
}
|
||||
// Do not do anything for default identity
|
||||
if (strcasecmp($args['record']['email'], $rc->user->data['username']) === 0)
|
||||
return $args;
|
||||
|
||||
// Process boolean fields
|
||||
$flags = 0;
|
||||
if (get_input_value('_ident_switch_form_enabled', RCUBE_INPUT_POST))
|
||||
$flags |= $this->db_enabled;
|
||||
if (get_input_value('_ident_switch_form_secure', RCUBE_INPUT_POST))
|
||||
$flags |= $this->db_secure;
|
||||
if (!rcube_utils::get_input_value('_ident_switch_form_enabled', rcube_utils::INPUT_POST))
|
||||
{
|
||||
self::sw_imap_off($args['id']);
|
||||
return $args;
|
||||
}
|
||||
|
||||
$rc->db->query(
|
||||
$sql,
|
||||
$flags,
|
||||
get_input_value('_ident_switch_form_label', RCUBE_INPUT_POST),
|
||||
get_input_value('_ident_switch_form_host', RCUBE_INPUT_POST),
|
||||
get_input_value('_ident_switch_form_port', RCUBE_INPUT_POST),
|
||||
get_input_value('_ident_switch_form_username', RCUBE_INPUT_POST),
|
||||
$rc->encrypt(get_input_value('_ident_switch_form_password', RCUBE_INPUT_POST)),
|
||||
get_input_value('_ident_switch_form_delimiter', RCUBE_INPUT_POST),
|
||||
$rc->user->ID,
|
||||
$args['id']
|
||||
);
|
||||
$data = self::check_field_values();
|
||||
if ($data['err'])
|
||||
{
|
||||
$this->add_texts('localization');
|
||||
$args['abort'] = true;
|
||||
$args['message'] = 'ident_switch.err.' . $data['err'];
|
||||
return $args;
|
||||
}
|
||||
|
||||
$data['id'] = $args['id'];
|
||||
self::save_field_values($rc, $data);
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function on_identity_create($args)
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
// Do not do anything for default identity
|
||||
if (strcasecmp($args['record']['email'], $rc->user->data['username']) === 0)
|
||||
return $args;
|
||||
|
||||
// Process boolean fields
|
||||
if (!rcube_utils::get_input_value('_ident_switch_form_enabled', rcube_utils::INPUT_POST))
|
||||
return $args;
|
||||
|
||||
$data = self::check_field_values();
|
||||
if ($data['err'])
|
||||
{
|
||||
$this->add_texts('localization');
|
||||
$args['abort'] = true;
|
||||
$args['message'] = 'ident_switch.err.' . $data['err'];
|
||||
}
|
||||
|
||||
// Save data for _after (cannot pass with $args)
|
||||
$_SESSION['createData' . self::MY_POSTFIX] = $data;
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function on_identity_create_after($args)
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
// Do not do anything for default identity
|
||||
if (strcasecmp($args['record']['email'], $rc->user->data['username']) === 0)
|
||||
return $args;
|
||||
|
||||
$data = $_SESSION['createData' . self::MY_POSTFIX];
|
||||
|
||||
unset($_SESSION['createData' . self::MY_POSTFIX]);
|
||||
if (!$data || count($data) == 0)
|
||||
self::write_log('Object with ident_switch values not found in session for ID = ' . $args['id'] . '.');
|
||||
else
|
||||
{
|
||||
$data['id'] = $args['id'];
|
||||
self::save_field_values($rc, $data);
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
@@ -197,57 +351,186 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
$sql = 'DELETE FROM ' . $rc->db->table_name($this->table) . ' WHERE iid = ? AND user_id = ?';
|
||||
$rc->db->query($sql, $args['id'], $rc->user->ID);
|
||||
$sql = 'DELETE FROM ' . $rc->db->table_name(self::TABLE) . ' WHERE iid = ? AND user_id = ?';
|
||||
$q = $rc->db->query($sql, $args['id'], $rc->user->ID);
|
||||
|
||||
// TODO: Affected rows count for log
|
||||
if ($rc->db->affected_rows($q))
|
||||
self::write_log('Deleted associated information for identity with ID = ' . $args['id'] . '.');
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function on_template_object_composeheaders($args)
|
||||
{
|
||||
if ($args['id'] == '_from')
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
if (strcasecmp($_SESSION['username'], $rc->user->data['username']) !== 0)
|
||||
{
|
||||
if (isset($_SESSION['iid' . self::MY_POSTFIX]))
|
||||
$rc->output->add_script('plugin_switchIdent_fixIdent(' . $_SESSION['iid' . self::MY_POSTFIX] . ');', 'docready');
|
||||
else
|
||||
self::write_log('Special session variable with active identity ID not found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function check_field_values()
|
||||
{
|
||||
$retVal = array();
|
||||
|
||||
$retVal['label'] = self::ntrim(rcube_utils::get_input_value('_ident_switch_form_label', rcube_utils::INPUT_POST));
|
||||
if (strlen($retVal['label']) > 32)
|
||||
$retVal['err'] = 'label.long';
|
||||
else
|
||||
{
|
||||
$retVal['host'] = self::ntrim(rcube_utils::get_input_value('_ident_switch_form_host', rcube_utils::INPUT_POST));
|
||||
if (strlen($retVal['host']) > 64)
|
||||
$retVal['err'] = 'host.long';
|
||||
else
|
||||
{
|
||||
$retVal['port'] = self::ntrim(rcube_utils::get_input_value('_ident_switch_form_port', rcube_utils::INPUT_POST));
|
||||
if ($retVal['port'] && !ctype_digit($retVal['port']))
|
||||
$retVal['err'] = 'port.num';
|
||||
else
|
||||
{
|
||||
if ($retVal['port'] && ($retVal['port'] <= 0 || $retVal['port'] > 65535))
|
||||
$retVal['err'] = 'port.range';
|
||||
else
|
||||
{
|
||||
$retVal['user'] = self::ntrim(rcube_utils::get_input_value('_ident_switch_form_username', rcube_utils::INPUT_POST));
|
||||
if (strlen($retVal['user']) > 64)
|
||||
$retVal['err'] = 'user.long';
|
||||
else
|
||||
{
|
||||
$retVal['delim'] = self::ntrim(rcube_utils::get_input_value('_ident_switch_form_delimiter', rcube_utils::INPUT_POST));
|
||||
if (strlen($retVal['delim']) > 1)
|
||||
$retVal['err'] = 'delim.long';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get also password
|
||||
$retVal['pass'] = rcube_utils::get_input_value('_ident_switch_form_password', rcube_utils::INPUT_POST);
|
||||
|
||||
// Parse secure settings
|
||||
$retVal['flags'] = self::DB_ENABLED;
|
||||
$ssl = rcube_utils::get_input_value('_ident_switch_form_secure', rcube_utils::INPUT_POST);
|
||||
if (strcasecmp($ssl, 'tls') === 0)
|
||||
$retVal['flags'] |= self::DB_SECURE_TLS;
|
||||
elseif (strcasecmp($ssl, 'ssl') === 0)
|
||||
$retVal['flags'] |= self::DB_SECURE_SSL;
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
|
||||
private static function save_field_values($rc, $data)
|
||||
{
|
||||
$sql = 'SELECT id, password FROM ' . $rc->db->table_name(self::TABLE) . ' WHERE iid = ? AND user_id = ?';
|
||||
$q = $rc->db->query($sql, $data['id'], $rc->user->ID);
|
||||
$r = $rc->db->fetch_assoc($q);
|
||||
if ($r)
|
||||
{ // Record already exists, will update it
|
||||
$sql = 'UPDATE ' .
|
||||
$rc->db->table_name(self::TABLE) .
|
||||
' SET flags = ?, label = ?, host = ?, port = ?, username = ?, password = ?, delimiter = ?, user_id = ?, iid = ?' .
|
||||
' WHERE id = ?';
|
||||
}
|
||||
else if ($data['flags'] & self::DB_ENABLED)
|
||||
{ // No record exists, create new one
|
||||
$sql = 'INSERT INTO ' .
|
||||
$rc->db->table_name(self::TABLE) .
|
||||
'(flags, label, host, port, username, password, delimiter, user_id, iid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
}
|
||||
|
||||
if ($sql)
|
||||
{
|
||||
// Do we need to update pwd?
|
||||
if ($data['pass'] != $r['password'])
|
||||
$data['pass'] = $rc->encrypt($data['pass']);
|
||||
|
||||
$rc->db->query(
|
||||
$sql,
|
||||
$data['flags'],
|
||||
$data['label'],
|
||||
$data['host'],
|
||||
$data['port'],
|
||||
$data['user'],
|
||||
$data['pass'],
|
||||
$data['delim'],
|
||||
$rc->user->ID,
|
||||
$data['id'],
|
||||
$r['id']
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function on_switch()
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
$my_postfix = '_iswitch';
|
||||
$my_postfix_len = strlen($my_postfix);
|
||||
|
||||
error_log('Switcing account!'); // TODO: Add nornal logging here!
|
||||
|
||||
$identId = rcube_utils::get_input_value('_ident-id', RCUBE_INPUT_POST);
|
||||
error_log($identId);
|
||||
$my_postfix_len = strlen(self::MY_POSTFIX);
|
||||
$identId = rcube_utils::get_input_value('_ident-id', rcube_utils::INPUT_POST);
|
||||
|
||||
if (-1 == $identId)
|
||||
{ // Switch to main account
|
||||
self::write_log('Switching mailbox back to default.');
|
||||
|
||||
// Restore everything with STORAGE*my_postfix
|
||||
foreach ($_SESSION as $k => $v)
|
||||
{
|
||||
if (strncasecmp($k, 'storage', 7) === 0 && substr_compare($k, $my_postfix, -$my_postfix_len, $my_postfix_len) === 0)
|
||||
if (strncasecmp($k, 'storage', 7) === 0 && substr_compare($k, self::MY_POSTFIX, -$my_postfix_len, $my_postfix_len) === 0)
|
||||
{
|
||||
error_log($k . '=>' . $v);
|
||||
$_SESSION[$k] = $_SESSION[$k . $my_postfix];
|
||||
$rc->session->remove($k . $my_postfix);
|
||||
$realKey = substr($k, 0, -$my_postfix_len);
|
||||
$_SESSION[$realKey] = $_SESSION[$k];
|
||||
$rc->session->remove($k);
|
||||
}
|
||||
}
|
||||
$_SESSION['username'] = $rc->user->data['username'];
|
||||
$_SESSION['password'] = $_SESSION['password' . $my_postfix];
|
||||
$_SESSION['password'] = $_SESSION['password' . self::MY_POSTFIX];
|
||||
$_SESSION['iid' . self::MY_POSTFIX] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql = 'SELECT host, flags, port, username, password FROM ' . $rc->db->table_name($this->table) . ' WHERE id = ? AND user_id = ?';
|
||||
$sql = 'SELECT host, flags, port, username, password, iid FROM ' . $rc->db->table_name(self::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))
|
||||
{
|
||||
$port = $r['port'];
|
||||
$ssl = false;
|
||||
if ($r['flags'] & $this->db_secure)
|
||||
{
|
||||
$ssl = true;
|
||||
if (!$port)
|
||||
$port = 993; // Default SSL/TLS port here!
|
||||
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'];
|
||||
}
|
||||
|
||||
self::write_log('Switching mailbox to one for identity with ID = ' . $r['iid'] . ' (username = \'' . $r['username'] . '\').');
|
||||
|
||||
$def_port = 143; // Default port here!
|
||||
$ssl = null;
|
||||
if ($r['flags'] & self::DB_SECURE_TLS)
|
||||
{
|
||||
$ssl = 'tls';
|
||||
$def_port = 143; // Default TLS port here!
|
||||
}
|
||||
elseif ($r['flags'] & self::DB_SECURE_SSL)
|
||||
{
|
||||
$ssl = 'ssl';
|
||||
$def_port = 993; // Default SSL port here!
|
||||
}
|
||||
|
||||
$port = $r['port'];
|
||||
if (!$port)
|
||||
$port = 143; // Default port here!
|
||||
$port = $def_port;
|
||||
|
||||
// If we are in default account now
|
||||
// save everything with STORAGE
|
||||
@@ -255,28 +538,30 @@ class ident_switch extends rcube_plugin
|
||||
{
|
||||
foreach ($_SESSION as $k => $v)
|
||||
{
|
||||
if (strncasecmp($k, 'storage', 7) === 0 && substr_compare($k, $my_postfix, -$my_postfix_len, $my_postfix_len) !== 0)
|
||||
if (strncasecmp($k, 'storage', 7) === 0 && substr_compare($k, self::MY_POSTFIX, -$my_postfix_len, $my_postfix_len) !== 0)
|
||||
{
|
||||
error_log($k . '=>' . $v);
|
||||
$_SESSION[$k . $my_postfix] = $_SESSION[$k];
|
||||
if (!$_SESSION[$k . self::MY_POSTFIX])
|
||||
$_SESSION[$k . self::MY_POSTFIX] = $_SESSION[$k];
|
||||
$rc->session->remove($k);
|
||||
}
|
||||
}
|
||||
}
|
||||
$_SESSION['password' . $my_postfix] = $_SESSION['password'];
|
||||
if (!$_SESSION['password' . self::MY_POSTFIX])
|
||||
$_SESSION['password' . self::MY_POSTFIX] = $_SESSION['password'];
|
||||
|
||||
$_SESSION['storage_host'] = $r['host'];
|
||||
$_SESSION['storage_host'] = $r['host'] ? $r['host'] : 'localhost'; // Default host here!
|
||||
$_SESSION['storage_ssl'] = $ssl;
|
||||
$_SESSION['storage_port'] = $port;
|
||||
$_SESSION['username'] = $r['username'];
|
||||
$_SESSION['password'] = $r['password'];
|
||||
$_SESSION['iid' . self::MY_POSTFIX] = $r['iid'];
|
||||
|
||||
$rc->session->remove('folders');
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Show message in browser
|
||||
error_log('Requested account not found!');
|
||||
self::write_log('Requested remote mailbox with ID = ' . $identId . ' not found.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -284,8 +569,102 @@ class ident_switch extends rcube_plugin
|
||||
$rc->output->redirect(
|
||||
array(
|
||||
'_task' => 'mail',
|
||||
'_mbox' => rcube_utils::get_input_value('_mbox', RCUBE_INPUT_GET),
|
||||
'_mbox' => 'INBOX',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static function sw_imap_off($iid)
|
||||
{
|
||||
$rc = rcmail::get_instance();
|
||||
|
||||
$sql = 'UPDATE ' . $rc->db->table_name(self::TABLE) . ' SET flags = flags & ? WHERE iid = ? AND user_id = ?';
|
||||
$rc->db->query($sql, ~self::DB_ENABLED, $iid, $rc->user->ID);
|
||||
}
|
||||
|
||||
private function get_preconfig($email)
|
||||
{
|
||||
$dom = substr(strstr($email, '@'), 1);
|
||||
if (!$dom)
|
||||
return false;
|
||||
|
||||
$this->load_config(); // config.inc.php
|
||||
|
||||
$cfg = rcmail::get_instance()->config->get('ident_switch.preconfig', array());
|
||||
$cfg = $cfg[$dom];
|
||||
|
||||
if ($cfg)
|
||||
{
|
||||
if (!$cfg['host'])
|
||||
return false; # Host must be specified!
|
||||
}
|
||||
return $cfg;
|
||||
}
|
||||
|
||||
private function apply_preconfig(&$record)
|
||||
{
|
||||
$email = $record['email'];
|
||||
$cfg = $this->get_preconfig($email);
|
||||
if (is_array($cfg))
|
||||
{
|
||||
self::write_log('Applying predefined configuration for \'' . $email . '\'.');
|
||||
|
||||
if ($cfg['host'])
|
||||
{ // Parse and set host and related
|
||||
$urlArr = parse_url($cfg['host']);
|
||||
|
||||
$record['ident_switch.form.host'] = $urlArr['host'] ? rcube::Q($urlArr['host'], 'url') : '';
|
||||
$record['ident_switch.form.port'] = $urlArr['port'] ? intval($urlArr['port']) : '';
|
||||
|
||||
if (strcasecmp('tls', $urlArr['scheme']) === 0)
|
||||
$record['ident_switch.form.secure'] = 'tls';
|
||||
elseif (strcasecmp('ssl', $urlArr['scheme']) === 0)
|
||||
$record['ident_switch.form.secure'] = 'ssl';
|
||||
else
|
||||
$record['ident_switch.form.secure'] = '';
|
||||
}
|
||||
|
||||
$loginSet = false;
|
||||
if ($cfg['user'])
|
||||
{ // Set up user name
|
||||
switch (strtoupper($cfg['user']))
|
||||
{
|
||||
case 'EMAIL':
|
||||
$record['ident_switch.form.username'] = $email;
|
||||
$loginSet = true;
|
||||
break;
|
||||
case 'MBOX':
|
||||
$record['ident_switch.form.username'] = strstr($email, '@', true);
|
||||
$loginSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cfg['readonly'])
|
||||
{
|
||||
$record['ident_switch.form.readonly'] = 1;
|
||||
if ($loginSet)
|
||||
$record['ident_switch.form.readonly'] = 2;
|
||||
}
|
||||
|
||||
return $cfg['readonly'];
|
||||
}
|
||||
}
|
||||
|
||||
private static function ntrim($str)
|
||||
{
|
||||
if (is_null($str))
|
||||
return $str;
|
||||
|
||||
$s = trim($str);
|
||||
if (!$s)
|
||||
return null;
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
private static function write_log($txt)
|
||||
{
|
||||
rcmail::get_instance()->write_log('ident_switch', $txt);
|
||||
}
|
||||
}
|
||||
|
||||
50
localization/de_DE.inc
Normal file
50
localization/de_DE.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Localization file for ident_switch plugin
|
||||
*/
|
||||
$labels = array();
|
||||
|
||||
// IMAP
|
||||
$labels['form.caption'] = 'IMAP';
|
||||
|
||||
// Enabled
|
||||
$labels['form.enabled'] = 'Aktiviert';
|
||||
|
||||
// Label
|
||||
$labels['form.label'] = 'Bezeichnung';
|
||||
|
||||
// Server host name
|
||||
$labels['form.host']='Servername';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure']='Verbindungssicherheit';
|
||||
|
||||
// Port
|
||||
$labels['form.port']='Port';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Benutzername';
|
||||
|
||||
// Password
|
||||
$labels['form.password'] = 'Passwort';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Hierachietrennzeichen für Verzeichnisse';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = 'Der Wert in Feld \'Bezeichnung\' im Abschnitt IMAP ist zu lang (max. 32 Zeichen).';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = 'Der Wert in Feld \'Servername\' im Abschnitt IMAP ist zu lang (max. 64 Zeichen).';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = 'Der Wert in Feld \'Benutzername\' im Abschnitt IMAP ist zu lang (max. 64 Zeichen).';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = 'Der Wert in Feld \'Hierachietrennzeichen für Verzeichnisse\' im Abschnitt IMAP ist zu lang (max. 1 Zeichen).';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = 'Der Wert in Feld \'Port\' im Abschnitt IMAP muss eine Zahl sein.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = 'Der Wert in Feld \'Port\' im Abschnitt IMAP muss 1 und 65535 liegen.';
|
||||
@@ -13,14 +13,38 @@ $labels['form.enabled'] = 'Enabled';
|
||||
// Label
|
||||
$labels['form.label'] = 'Label';
|
||||
|
||||
// Server URI
|
||||
$labels['form.server']='Server URI';
|
||||
// Server host name
|
||||
$labels['form.host']='Server host name';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure']='Connection security';
|
||||
|
||||
// Port
|
||||
$labels['form.port']='Port';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Username';
|
||||
|
||||
// Passwotrd
|
||||
// Password
|
||||
$labels['form.password'] = 'Password';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Folder hierarchy delimiter';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = 'Value in \'Label\' field of IMAP section is too long (32 chars max).';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = 'Value in \'Server host name\' field of IMAP section is too long (64 chars max).';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = 'Value in \'Username\' field of IMAP section is too long (64 chars max).';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = 'Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = 'Value in \'Port\' field of IMAP section must be a number.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = 'Value in \'Port\' field of IMAP section must be between 1 and 65535.';
|
||||
|
||||
50
localization/fr_FR.inc
Normal file
50
localization/fr_FR.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Localization file for ident_switch plugin
|
||||
*/
|
||||
$labels = array();
|
||||
|
||||
// IMAP
|
||||
$labels['form.caption'] = 'IMAP';
|
||||
|
||||
// Enabled
|
||||
$labels['form.enabled'] = 'Activé';
|
||||
|
||||
// Label
|
||||
$labels['form.label'] = 'Nom d\'affichage';
|
||||
|
||||
// Server host name
|
||||
$labels['form.host']='Nom d\'hôte du serveur';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure']='Sécurité de la connexion';
|
||||
|
||||
// Port
|
||||
$labels['form.port']='Port';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Nom d\'utilisateur';
|
||||
|
||||
// Password
|
||||
$labels['form.password'] = 'Mot de passe';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Délimiteur de la hiérarchie des dossiers';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = 'La valeur du champ \'Nom d\'affichage\' de la section IMAP est trop longue (32 car. max).';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = 'La valeur du champ \'Nom d\'hôte du serveur\' de la section IMAP est trop longue (64 car. max).';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = 'La valeur du champ \'Nom d\'utilisateur\' de la section IMAP est trop longue (64 car. max).';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = 'La valeur du champ \'Délimiteur de la hiérarchie des dossiers\' de la section IMAP est trop longue (1 car. max).';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = 'La valeur du champ \'Port\' de la section IMAP doit être un nombre.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = 'La valeur du champ \'Port\' de la section IMAP doit être comprise entre 1 et 65535.';
|
||||
50
localization/it_IT.inc
Normal file
50
localization/it_IT.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Localization file for ident_switch plugin
|
||||
*/
|
||||
$labels = array();
|
||||
|
||||
// IMAP
|
||||
$labels['form.caption'] = 'IMAP';
|
||||
|
||||
// Enabled
|
||||
$labels['form.enabled'] = 'Abilita';
|
||||
|
||||
// Label
|
||||
$labels['form.label'] = 'Nome visualizzato';
|
||||
|
||||
// Server host name
|
||||
$labels['form.host']='Nome del server';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure']='Sicurezza della connessione';
|
||||
|
||||
// Port
|
||||
$labels['form.port']='Porta';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Username';
|
||||
|
||||
// Password
|
||||
$labels['form.password'] = 'Password';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Delimitatore gerarchico delle cartelle';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = 'Il valore del campo \' Nome Visualizzato\' è troppo lungo. (massimo 32 caratteri).';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = 'Il valore del campo \'Nome del server\' della sezione IMAP è troppo lungo (massimo 64 caratteri).';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = 'Il valore del campo \'Username\' della sezione IMAP è troppo lungo (massimo 64 caratteri).';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = 'Il valore del campo \'Delimitatore gerarchico delle cartelle\' è troppo lungo (massimo 1 carattere).';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = 'Il valore del campo \'Porta\' nella sezione IMAP deve essere un numero.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = 'Il valore del campo \'Porta\' nella sezione IMAP deve essere compreso tra i valori 1 e 65535.';
|
||||
50
localization/nl_NL.inc
Normal file
50
localization/nl_NL.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Localization file for ident_switch plugin
|
||||
*/
|
||||
$labels = array();
|
||||
|
||||
// IMAP
|
||||
$labels['form.caption'] = 'IMAP';
|
||||
|
||||
// Enabled
|
||||
$labels['form.enabled'] = 'Inschakelen';
|
||||
|
||||
// Label
|
||||
$labels['form.label'] = 'Label';
|
||||
|
||||
// Server host name
|
||||
$labels['form.host']='Servernaam';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure']='Beveiligingstype';
|
||||
|
||||
// Port
|
||||
$labels['form.port']='Poortnummer';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Gebruikersnaam';
|
||||
|
||||
// Password
|
||||
$labels['form.password'] = 'Wachtwoord';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Map hiërarchie scheidingsteken';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = 'De waarde in het veld \'Label\' is te lang! (maximaal 32 karakter is toegestaan).';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = 'De waarde in het veld \'Servernaam\' is te lang (maximaal 64 karakter is toegestaan).';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = 'De waarde in het veld \'Gebruikersnaam\' is te lang! (maximaal 64 karakter is toegestaan).';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = 'De waarde in het veld \'Map hiërarchie scheidingsteken\' is te lang! (maximaal 1 karakter is toegestaan).';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = 'De waarde in het veld \'Poortnummer\' moet een nummer zijn.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = 'De waarde in het veld \'Poortnummer\' moet tussen de 1 en 65535 zijn.';
|
||||
50
localization/ru_RU.inc
Normal file
50
localization/ru_RU.inc
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/*
|
||||
* Localization file for ident_switch plugin
|
||||
*/
|
||||
$labels = array();
|
||||
|
||||
// IMAP
|
||||
$labels['form.caption'] = 'IMAP';
|
||||
|
||||
// Enabled
|
||||
$labels['form.enabled'] = 'Включено';
|
||||
|
||||
// Label
|
||||
$labels['form.label'] = 'Название';
|
||||
|
||||
// Server host name
|
||||
$labels['form.host'] = 'Адрес сервера';
|
||||
|
||||
// Secure connection (SSL/TLS)
|
||||
$labels['form.secure'] = 'Защита подключения';
|
||||
|
||||
// Port
|
||||
$labels['form.port'] = 'Порт';
|
||||
|
||||
// Username
|
||||
$labels['form.username'] = 'Имя пользователя';
|
||||
|
||||
// Password
|
||||
$labels['form.password'] = 'Пароль';
|
||||
|
||||
// Folder hierarchy delimiter
|
||||
$labels['form.delimiter'] = 'Разделитель в иерархии папок';
|
||||
|
||||
// Value in \'Label\' field of IMAP section is too long (32 chars max).
|
||||
$labels['err.label.long'] = '\'Название\' в разделе IMAP должно быть не длинее 32 символов.';
|
||||
|
||||
// Value in \'Server host name\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.host.long'] = '\'Адрес сервера\' в разделе IMAP должен быть не длинее 64 символов.';
|
||||
|
||||
// Value in \'Username\' field of IMAP section is too long (64 chars max).
|
||||
$labels['err.user.long'] = '\'Имя пользователя\' в секции IMAP должно быть не длинее 64 символов.';
|
||||
|
||||
// Value in \'Folder hierarchy delimiter\' field of IMAP section is too long (1 char max).
|
||||
$labels['err.delim.long'] = '\'Разделитель в иерархии папок\' в секции IMAP должен быть не длинее 1 символа.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be a number.
|
||||
$labels['err.port.num'] = '\'Порт\' в секции IMAP должен быть числом.';
|
||||
|
||||
// Value in \'Port\' field of IMAP section must be between 1 and 65535.
|
||||
$labels['err.port.range'] = '\'Порт\' в секции IMAP должен быть в диапазоне от 1 до 65535.';
|
||||
@@ -1,15 +0,0 @@
|
||||
/***************************************************************************
|
||||
* This file is part of Roundcube "identities_imap" plugin.
|
||||
*
|
||||
* Your are not allowed to distribute this file or parts of it.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Copyright (c) 2012 - 2014 Roland 'Rosali' Liebl - all rights reserved
|
||||
* dev-team [at] myroundcube [dot] com
|
||||
* http://myroundcube.com
|
||||
***************************************************************************/
|
||||
|
||||
#accounts{position:absolute; top:63px; left:18px;}.remotehint{z-index:-1; position:absolute; top:7px; margin-left:auto; left:210px; width:400px; border-radius:5px; padding:4px; -moz-border-radius:5px; border:1px solid #DEEEFC; background:#F2F9FF; text-align:center; color:#3F70BA; display:inline;}.classic{top:2px;}
|
||||
@@ -1,15 +0,0 @@
|
||||
/***************************************************************************
|
||||
* This file is part of Roundcube "identities_imap" plugin.
|
||||
*
|
||||
* Your are not allowed to distribute this file or parts of it.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Copyright (c) 2012 - 2014 Roland 'Rosali' Liebl - all rights reserved
|
||||
* dev-team [at] myroundcube [dot] com
|
||||
* http://myroundcube.com
|
||||
***************************************************************************/
|
||||
|
||||
select.deco{height:18px; font-size:12px; border-radius:3px; -moz-border-radius:3px; -webkit-border-radius:3px; color:#fff; background:#444; border:1px solid #ababab;}.remotehint{z-index:1; position:absolute; top:1px; margin-left:auto; left:50%; margin-left:-200px; width:400px; border-radius:5px; padding:4px; -moz-border-radius:5px; border:1px solid #DEEEFC; background:#F2F9FF; text-align:center; color:#3F70BA; display:inline;}
|
||||
@@ -1,15 +0,0 @@
|
||||
/***************************************************************************
|
||||
* This file is part of Roundcube "##PLUGIN##" plugin.
|
||||
*
|
||||
* Your are not allowed to distribute this file or parts of it.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Copyright (c) 2012 - ##YEAR## Roland 'Rosali' Liebl - all rights reserved
|
||||
* dev-team [at] myroundcube [dot] com
|
||||
* http://myroundcube.com
|
||||
***************************************************************************/
|
||||
|
||||
select.deco{}#taskbar .remotehint{position:absolute; top:52px; left:50%; margin-left:-200px; width:400px; padding:0px; border:1px solid #DEEEFC; background-color:#F2F9FF; text-align:center; font-size:10px; color:#3F70BA;}
|
||||
Reference in New Issue
Block a user