diff --git a/data/Dockerfiles/dockerapi/dockerapi.py b/data/Dockerfiles/dockerapi/dockerapi.py index 6d3b1012..1ab651b5 100644 --- a/data/Dockerfiles/dockerapi/dockerapi.py +++ b/data/Dockerfiles/dockerapi/dockerapi.py @@ -381,11 +381,14 @@ class DockerUtils: for container in self.docker_client.containers.list(filters={"id": container_id}): sane_name = re.sub(r'\W+', '', request_json['maildir']) vmail_name = request_json['maildir'].replace("'", "'\\''") - index_name = request_json['maildir'].split("/") - index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''") cmd_vmail = "if [[ -d '/var/vmail/" + vmail_name + "' ]]; then /bin/mv '/var/vmail/" + vmail_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi" - cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "_index'; fi" - cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index] + index_name = request_json['maildir'].split("/") + if len(index_name) > 1: + index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''") + cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "_index'; fi" + cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index] + else: + cmd = ["/bin/bash", "-c", cmd_vmail] maildir_cleanup = container.exec_run(cmd, user='vmail') return exec_run_handler('generic', maildir_cleanup) # api call: container_post - post_action: exec - cmd: rspamd - task: worker_password diff --git a/data/web/css/build/011-datatables.css b/data/web/css/build/011-datatables.css index d03514ff..d262f07c 100644 --- a/data/web/css/build/011-datatables.css +++ b/data/web/css/build/011-datatables.css @@ -342,6 +342,10 @@ div.dataTables_wrapper div.dt-row { position: relative; } +div.dataTables_wrapper span.sorting-value { + display: none; +} + div.dataTables_scrollHead table.dataTable { margin-bottom: 0 !important; } diff --git a/data/web/css/site/mailbox.css b/data/web/css/site/mailbox.css index f62ead31..e896abca 100644 --- a/data/web/css/site/mailbox.css +++ b/data/web/css/site/mailbox.css @@ -66,4 +66,6 @@ table tbody tr td input[type="checkbox"] { padding: .2em .4em .3em !important; background-color: #ececec!important; } - +.badge.bg-info .bi { + font-size: inherit; +} diff --git a/data/web/css/themes/mailcow-darkmode.css b/data/web/css/themes/mailcow-darkmode.css index 6e0db0e9..abaa7499 100644 --- a/data/web/css/themes/mailcow-darkmode.css +++ b/data/web/css/themes/mailcow-darkmode.css @@ -20,6 +20,11 @@ legend { background-color: #7a7a7a !important; border-color: #5c5c5c !important; } +.btn-dark { + color: #000 !important;; + background-color: #f6f6f6 !important;; + border-color: #ddd !important;; +} .btn-check:checked+.btn-secondary, .btn-check:active+.btn-secondary, .btn-secondary:active, .btn-secondary.active, .show>.btn-secondary.dropdown-toggle { border-color: #7a7a7a !important; } @@ -299,22 +304,22 @@ a:hover { } -table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover, +table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover, table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover { background-color: #7a7a7a !important; } -table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before, +table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before, table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before { background-color: #7a7a7a !important; border: 1.5px solid #5c5c5c !important; color: #fff !important; } -table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before, +table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before, table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before { background-color: #949494; } -table.dataTable.dtr-inline.collapsed>tbody>tr>td.child, -table.dataTable.dtr-inline.collapsed>tbody>tr>th.child, +table.dataTable.dtr-inline.collapsed>tbody>tr>td.child, +table.dataTable.dtr-inline.collapsed>tbody>tr>th.child, table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty { background-color: #444444; } @@ -327,7 +332,7 @@ table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty { } .btn.btn-outline-secondary { color: #fff !important; - border-color: #7a7a7a !important; + border-color: #7a7a7a !important; } .btn-check:checked+.btn-outline-secondary, .btn-check:active+.btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { background-color: #9b9b9b !important; diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index de1855fa..4dc2418c 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -1015,20 +1015,58 @@ function formatBytes($size, $precision = 2) { } return round(pow(1024, $base - floor($base)), $precision) . $suffixes[floor($base)]; } -function update_sogo_static_view() { +function update_sogo_static_view($mailbox = null) { if (getenv('SKIP_SOGO') == "y") { return true; } global $pdo; global $lang; - $stmt = $pdo->query("SELECT 'OK' FROM INFORMATION_SCHEMA.TABLES - WHERE TABLE_NAME = 'sogo_view'"); - $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC)); - if ($num_results != 0) { - $stmt = $pdo->query("REPLACE INTO _sogo_static_view (`c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings`) - SELECT `c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings` from sogo_view"); - $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); + + $mailbox_exists = false; + if ($mailbox !== null) { + // Check if the mailbox exists + $stmt = $pdo->prepare("SELECT username FROM mailbox WHERE username = :mailbox AND active = '1'"); + $stmt->execute(array(':mailbox' => $mailbox)); + $row = $stmt->fetch(PDO::FETCH_ASSOC); + if ($row){ + $mailbox_exists = true; + } } + + $query = "REPLACE INTO _sogo_static_view (`c_uid`, `domain`, `c_name`, `c_password`, `c_cn`, `mail`, `aliases`, `ad_aliases`, `ext_acl`, `kind`, `multiple_bookings`) + SELECT + mailbox.username, + mailbox.domain, + mailbox.username, + IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.force_pw_update')) = '0', + IF(JSON_UNQUOTE(JSON_VALUE(attributes, '$.sogo_access')) = 1, password, '{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'), + '{SSHA256}A123A123A321A321A321B321B321B123B123B321B432F123E321123123321321'), + mailbox.name, + mailbox.username, + IFNULL(GROUP_CONCAT(ga.aliases ORDER BY ga.aliases SEPARATOR ' '), ''), + IFNULL(gda.ad_alias, ''), + IFNULL(external_acl.send_as_acl, ''), + mailbox.kind, + mailbox.multiple_bookings + FROM + mailbox + LEFT OUTER JOIN grouped_mail_aliases ga ON ga.username REGEXP CONCAT('(^|,)', mailbox.username, '($|,)') + LEFT OUTER JOIN grouped_domain_alias_address gda ON gda.username = mailbox.username + LEFT OUTER JOIN grouped_sender_acl_external external_acl ON external_acl.username = mailbox.username + WHERE + mailbox.active = '1'"; + + if ($mailbox_exists) { + $query .= " AND mailbox.username = :mailbox"; + $stmt = $pdo->prepare($query); + $stmt->execute(array(':mailbox' => $mailbox)); + } else { + $query .= " GROUP BY mailbox.username"; + $stmt = $pdo->query($query); + } + + $stmt = $pdo->query("DELETE FROM _sogo_static_view WHERE `c_uid` NOT IN (SELECT `username` FROM `mailbox` WHERE `active` = '1');"); + flush_memcached(); } function edit_user_account($_data) { diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php index 4529ee7b..4e036b99 100644 --- a/data/web/inc/functions.mailbox.inc.php +++ b/data/web/inc/functions.mailbox.inc.php @@ -1264,11 +1264,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { )); } + update_sogo_static_view($username); $_SESSION['return'][] = array( 'type' => 'success', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'msg' => array('mailbox_added', htmlspecialchars($username)) ); + return true; break; case 'resource': $domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46); @@ -3130,7 +3132,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'msg' => array('mailbox_modified', $username) ); + + update_sogo_static_view($username); } + return true; break; case 'mailbox_templates': if ($_SESSION['mailcow_cc_role'] != "admin") { @@ -5053,12 +5058,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { ); continue; } + + update_sogo_static_view($username); $_SESSION['return'][] = array( 'type' => 'success', 'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr), 'msg' => array('mailbox_removed', htmlspecialchars($username)) ); } + return true; break; case 'mailbox_templates': if ($_SESSION['mailcow_cc_role'] != "admin") { @@ -5264,7 +5272,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) { } break; } - if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'mailbox', 'resource')) && getenv('SKIP_SOGO') != "y") { + if ($_action != 'get' && in_array($_type, array('domain', 'alias', 'alias_domain', 'resource')) && getenv('SKIP_SOGO') != "y") { update_sogo_static_view(); } } diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index 23ef1d25..07dfed8c 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -117,8 +117,8 @@ jQuery(function($){ data: 'tfa_active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { @@ -126,8 +126,8 @@ jQuery(function($){ data: 'active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { @@ -260,8 +260,8 @@ jQuery(function($){ data: 'tfa_active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { @@ -269,8 +269,8 @@ jQuery(function($){ data: 'active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { @@ -337,7 +337,7 @@ jQuery(function($){ data: 'keep_spam', defaultContent: '', render: function(data, type){ - return 'yes'==data?'':'no'==data&&''; + return 'yes'==data?'yes':'no'==data&&'no'; } }, { @@ -414,8 +414,8 @@ jQuery(function($){ data: 'active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { @@ -492,8 +492,8 @@ jQuery(function($){ data: 'active', defaultContent: '', render: function (data, type) { - if(data == 1) return ''; - else return ''; + if(data == 1) return '1'; + else return '0'; } }, { diff --git a/data/web/js/site/mailbox.js b/data/web/js/site/mailbox.js index f4039268..d7fca848 100644 --- a/data/web/js/site/mailbox.js +++ b/data/web/js/site/mailbox.js @@ -607,7 +607,7 @@ jQuery(function($){ defaultContent: '', responsivePriority: 6, render: function (data, type) { - return 1==data?'':(0==data?'':2==data&&'—'); + return 1==data?'1':(0==data?'0':2==data&&'—'); } }, { @@ -754,7 +754,7 @@ jQuery(function($){ data: 'attributes.gal', defaultContent: '', render: function (data, type) { - return 1==data?'':''; + return 1==data?'1':'0'; } }, { @@ -762,7 +762,7 @@ jQuery(function($){ data: 'attributes.backupmx', defaultContent: '', render: function (data, type) { - return 1==data?'':''; + return 1==data?'1':'0'; } }, { @@ -770,7 +770,7 @@ jQuery(function($){ data: 'attributes.relay_all_recipients', defaultContent: '', render: function (data, type) { - return 1==data?'':''; + return 1==data?'1':'0'; } }, { @@ -778,7 +778,7 @@ jQuery(function($){ data: 'attributes.relay_unknown_only', defaultContent: '', render: function (data, type) { - return 1==data?'':''; + return 1==data?'1':'0'; } }, { @@ -787,7 +787,7 @@ jQuery(function($){ defaultContent: '', responsivePriority: 4, render: function (data, type) { - return 1==data?'':''; + return 1==data?'1':'0'; } }, { @@ -1093,7 +1093,7 @@ jQuery(function($){ defaultContent: '', responsivePriority: 4, render: function (data, type) { - return 1==data?'':(0==data?'':2==data&&'—'); + return 1==data?'1':(0==data?'0':2==data&&'—'); } }, { @@ -1164,13 +1164,13 @@ jQuery(function($){ item.attributes.quota = humanFileSize(item.attributes.quota); - item.attributes.tls_enforce_in = ''; - item.attributes.tls_enforce_out = ''; - item.attributes.pop3_access = ''; - item.attributes.imap_access = ''; - item.attributes.smtp_access = ''; - item.attributes.sieve_access = ''; - item.attributes.sogo_access = ''; + item.attributes.tls_enforce_in = '' + (item.attributes.tls_enforce_in == 1 ? '1' : '0') + ''; + item.attributes.tls_enforce_out = '' + (item.attributes.tls_enforce_out == 1 ? '1' : '0') + ''; + item.attributes.pop3_access = '' + (item.attributes.pop3_access == 1 ? '1' : '0') + ''; + item.attributes.imap_access = '' + (item.attributes.imap_access == 1 ? '1' : '0') + ''; + item.attributes.smtp_access = '' + (item.attributes.smtp_access == 1 ? '1' : '0') + ''; + item.attributes.sieve_access = '' + (item.attributes.sieve_access == 1 ? '1' : '0') + ''; + item.attributes.sogo_access = '' + (item.attributes.sogo_access == 1 ? '1' : '0') + ''; if (item.attributes.quarantine_notification === 'never') { item.attributes.quarantine_notification = lang.never; } else if (item.attributes.quarantine_notification === 'hourly') { @@ -1188,7 +1188,6 @@ jQuery(function($){ item.attributes.quarantine_category = lang.q_all; } - if (item.template.toLowerCase() == "default"){ item.action = '