Mercurial > hg > rc1
comparison plugins/acl/acl.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:50:29 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1e000243b222 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 * Folders Access Control Lists Management (RFC4314, RFC2086) | |
| 5 * | |
| 6 * @author Aleksander Machniak <alec@alec.pl> | |
| 7 * | |
| 8 * Copyright (C) 2011-2012, Kolab Systems AG | |
| 9 * | |
| 10 * This program is free software: you can redistribute it and/or modify | |
| 11 * it under the terms of the GNU General Public License as published by | |
| 12 * the Free Software Foundation, either version 3 of the License, or | |
| 13 * (at your option) any later version. | |
| 14 * | |
| 15 * This program is distributed in the hope that it will be useful, | |
| 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 18 * GNU General Public License for more details. | |
| 19 * | |
| 20 * You should have received a copy of the GNU General Public License | |
| 21 * along with this program. If not, see http://www.gnu.org/licenses/. | |
| 22 */ | |
| 23 | |
| 24 class acl extends rcube_plugin | |
| 25 { | |
| 26 public $task = 'settings|addressbook|calendar'; | |
| 27 | |
| 28 private $rc; | |
| 29 private $supported = null; | |
| 30 private $mbox; | |
| 31 private $ldap; | |
| 32 private $specials = array('anyone', 'anonymous'); | |
| 33 | |
| 34 /** | |
| 35 * Plugin initialization | |
| 36 */ | |
| 37 function init() | |
| 38 { | |
| 39 $this->rc = rcmail::get_instance(); | |
| 40 | |
| 41 // Register hooks | |
| 42 $this->add_hook('folder_form', array($this, 'folder_form')); | |
| 43 // kolab_addressbook plugin | |
| 44 $this->add_hook('addressbook_form', array($this, 'folder_form')); | |
| 45 $this->add_hook('calendar_form_kolab', array($this, 'folder_form')); | |
| 46 // Plugin actions | |
| 47 $this->register_action('plugin.acl', array($this, 'acl_actions')); | |
| 48 $this->register_action('plugin.acl-autocomplete', array($this, 'acl_autocomplete')); | |
| 49 } | |
| 50 | |
| 51 /** | |
| 52 * Handler for plugin actions (AJAX) | |
| 53 */ | |
| 54 function acl_actions() | |
| 55 { | |
| 56 $action = trim(rcube_utils::get_input_value('_act', rcube_utils::INPUT_GPC)); | |
| 57 | |
| 58 // Connect to IMAP | |
| 59 $this->rc->storage_init(); | |
| 60 | |
| 61 // Load localization and configuration | |
| 62 $this->add_texts('localization/'); | |
| 63 $this->load_config(); | |
| 64 | |
| 65 if ($action == 'save') { | |
| 66 $this->action_save(); | |
| 67 } | |
| 68 else if ($action == 'delete') { | |
| 69 $this->action_delete(); | |
| 70 } | |
| 71 else if ($action == 'list') { | |
| 72 $this->action_list(); | |
| 73 } | |
| 74 | |
| 75 // Only AJAX actions | |
| 76 $this->rc->output->send(); | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Handler for user login autocomplete request | |
| 81 */ | |
| 82 function acl_autocomplete() | |
| 83 { | |
| 84 $this->load_config(); | |
| 85 | |
| 86 $search = rcube_utils::get_input_value('_search', rcube_utils::INPUT_GPC, true); | |
| 87 $reqid = rcube_utils::get_input_value('_reqid', rcube_utils::INPUT_GPC); | |
| 88 $users = array(); | |
| 89 $keys = array(); | |
| 90 | |
| 91 if ($this->init_ldap()) { | |
| 92 $max = (int) $this->rc->config->get('autocomplete_max', 15); | |
| 93 $mode = (int) $this->rc->config->get('addressbook_search_mode'); | |
| 94 | |
| 95 $this->ldap->set_pagesize($max); | |
| 96 $result = $this->ldap->search('*', $search, $mode); | |
| 97 | |
| 98 foreach ($result->records as $record) { | |
| 99 $user = $record['uid']; | |
| 100 | |
| 101 if (is_array($user)) { | |
| 102 $user = array_filter($user); | |
| 103 $user = $user[0]; | |
| 104 } | |
| 105 | |
| 106 if ($user) { | |
| 107 $display = rcube_addressbook::compose_search_name($record); | |
| 108 $user = array('name' => $user, 'display' => $display); | |
| 109 $users[] = $user; | |
| 110 $keys[] = $display ?: $user['name']; | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 if ($this->rc->config->get('acl_groups')) { | |
| 115 $prefix = $this->rc->config->get('acl_group_prefix'); | |
| 116 $group_field = $this->rc->config->get('acl_group_field', 'name'); | |
| 117 $result = $this->ldap->list_groups($search, $mode); | |
| 118 | |
| 119 foreach ($result as $record) { | |
| 120 $group = $record['name']; | |
| 121 $group_id = is_array($record[$group_field]) ? $record[$group_field][0] : $record[$group_field]; | |
| 122 | |
| 123 if ($group) { | |
| 124 $users[] = array('name' => ($prefix ?: '') . $group_id, 'display' => $group, 'type' => 'group'); | |
| 125 $keys[] = $group; | |
| 126 } | |
| 127 } | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 if (count($users)) { | |
| 132 // sort users index | |
| 133 asort($keys, SORT_LOCALE_STRING); | |
| 134 // re-sort users according to index | |
| 135 foreach ($keys as $idx => $val) { | |
| 136 $keys[$idx] = $users[$idx]; | |
| 137 } | |
| 138 $users = array_values($keys); | |
| 139 } | |
| 140 | |
| 141 $this->rc->output->command('ksearch_query_results', $users, $search, $reqid); | |
| 142 $this->rc->output->send(); | |
| 143 } | |
| 144 | |
| 145 /** | |
| 146 * Handler for 'folder_form' hook | |
| 147 * | |
| 148 * @param array $args Hook arguments array (form data) | |
| 149 * | |
| 150 * @return array Hook arguments array | |
| 151 */ | |
| 152 function folder_form($args) | |
| 153 { | |
| 154 $mbox_imap = $args['options']['name']; | |
| 155 $myrights = $args['options']['rights']; | |
| 156 | |
| 157 // Edited folder name (empty in create-folder mode) | |
| 158 if (!strlen($mbox_imap)) { | |
| 159 return $args; | |
| 160 } | |
| 161 /* | |
| 162 // Do nothing on protected folders (?) | |
| 163 if ($args['options']['protected']) { | |
| 164 return $args; | |
| 165 } | |
| 166 */ | |
| 167 // Get MYRIGHTS | |
| 168 if (empty($myrights)) { | |
| 169 return $args; | |
| 170 } | |
| 171 | |
| 172 // Load localization and include scripts | |
| 173 $this->load_config(); | |
| 174 $this->specials = $this->rc->config->get('acl_specials', $this->specials); | |
| 175 $this->add_texts('localization/', array('deleteconfirm', 'norights', | |
| 176 'nouser', 'deleting', 'saving', 'newuser', 'editperms')); | |
| 177 $this->rc->output->add_label('save', 'cancel'); | |
| 178 $this->include_script('acl.js'); | |
| 179 $this->rc->output->include_script('list.js'); | |
| 180 $this->include_stylesheet($this->local_skin_path().'/acl.css'); | |
| 181 | |
| 182 // add Info fieldset if it doesn't exist | |
| 183 if (!isset($args['form']['props']['fieldsets']['info'])) | |
| 184 $args['form']['props']['fieldsets']['info'] = array( | |
| 185 'name' => $this->rc->gettext('info'), | |
| 186 'content' => array()); | |
| 187 | |
| 188 // Display folder rights to 'Info' fieldset | |
| 189 $args['form']['props']['fieldsets']['info']['content']['myrights'] = array( | |
| 190 'label' => rcube::Q($this->gettext('myrights')), | |
| 191 'value' => $this->acl2text($myrights) | |
| 192 ); | |
| 193 | |
| 194 // Return if not folder admin | |
| 195 if (!in_array('a', $myrights)) { | |
| 196 return $args; | |
| 197 } | |
| 198 | |
| 199 // The 'Sharing' tab | |
| 200 $this->mbox = $mbox_imap; | |
| 201 $this->rc->output->set_env('acl_users_source', (bool) $this->rc->config->get('acl_users_source')); | |
| 202 $this->rc->output->set_env('mailbox', $mbox_imap); | |
| 203 $this->rc->output->add_handlers(array( | |
| 204 'acltable' => array($this, 'templ_table'), | |
| 205 'acluser' => array($this, 'templ_user'), | |
| 206 'aclrights' => array($this, 'templ_rights'), | |
| 207 )); | |
| 208 | |
| 209 $this->rc->output->set_env('autocomplete_max', (int)$this->rc->config->get('autocomplete_max', 15)); | |
| 210 $this->rc->output->set_env('autocomplete_min_length', $this->rc->config->get('autocomplete_min_length')); | |
| 211 $this->rc->output->add_label('autocompletechars', 'autocompletemore'); | |
| 212 | |
| 213 $args['form']['sharing'] = array( | |
| 214 'name' => rcube::Q($this->gettext('sharing')), | |
| 215 'content' => $this->rc->output->parse('acl.table', false, false), | |
| 216 ); | |
| 217 | |
| 218 return $args; | |
| 219 } | |
| 220 | |
| 221 /** | |
| 222 * Creates ACL rights table | |
| 223 * | |
| 224 * @param array $attrib Template object attributes | |
| 225 * | |
| 226 * @return string HTML Content | |
| 227 */ | |
| 228 function templ_table($attrib) | |
| 229 { | |
| 230 if (empty($attrib['id'])) | |
| 231 $attrib['id'] = 'acl-table'; | |
| 232 | |
| 233 $out = $this->list_rights($attrib); | |
| 234 | |
| 235 $this->rc->output->add_gui_object('acltable', $attrib['id']); | |
| 236 | |
| 237 return $out; | |
| 238 } | |
| 239 | |
| 240 /** | |
| 241 * Creates ACL rights form (rights list part) | |
| 242 * | |
| 243 * @param array $attrib Template object attributes | |
| 244 * | |
| 245 * @return string HTML Content | |
| 246 */ | |
| 247 function templ_rights($attrib) | |
| 248 { | |
| 249 // Get supported rights | |
| 250 $supported = $this->rights_supported(); | |
| 251 | |
| 252 // give plugins the opportunity to adjust this list | |
| 253 $data = $this->rc->plugins->exec_hook('acl_rights_supported', | |
| 254 array('rights' => $supported, 'folder' => $this->mbox, 'labels' => array())); | |
| 255 $supported = $data['rights']; | |
| 256 | |
| 257 // depending on server capability either use 'te' or 'd' for deleting msgs | |
| 258 $deleteright = implode(array_intersect(str_split('ted'), $supported)); | |
| 259 | |
| 260 $out = ''; | |
| 261 $ul = ''; | |
| 262 $input = new html_checkbox(); | |
| 263 | |
| 264 // Advanced rights | |
| 265 $attrib['id'] = 'advancedrights'; | |
| 266 foreach ($supported as $key => $val) { | |
| 267 $id = "acl$val"; | |
| 268 $ul .= html::tag('li', null, | |
| 269 $input->show('', array( | |
| 270 'name' => "acl[$val]", 'value' => $val, 'id' => $id)) | |
| 271 . html::label(array('for' => $id, 'title' => $this->gettext('longacl'.$val)), | |
| 272 $this->gettext('acl'.$val))); | |
| 273 } | |
| 274 | |
| 275 $out = html::tag('ul', $attrib, $ul, html::$common_attrib); | |
| 276 | |
| 277 // Simple rights | |
| 278 $ul = ''; | |
| 279 $attrib['id'] = 'simplerights'; | |
| 280 $items = array( | |
| 281 'read' => 'lrs', | |
| 282 'write' => 'wi', | |
| 283 'delete' => $deleteright, | |
| 284 'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)), | |
| 285 ); | |
| 286 | |
| 287 // give plugins the opportunity to adjust this list | |
| 288 $data = $this->rc->plugins->exec_hook('acl_rights_simple', | |
| 289 array('rights' => $items, 'folder' => $this->mbox, 'labels' => array(), 'titles' => array())); | |
| 290 | |
| 291 foreach ($data['rights'] as $key => $val) { | |
| 292 $id = "acl$key"; | |
| 293 $ul .= html::tag('li', null, | |
| 294 $input->show('', array( | |
| 295 'name' => "acl[$val]", 'value' => $val, 'id' => $id)) | |
| 296 . html::label(array('for' => $id, 'title' => $data['titles'][$key] ?: $this->gettext('longacl'.$key)), | |
| 297 $data['labels'][$key] ?: $this->gettext('acl'.$key))); | |
| 298 } | |
| 299 | |
| 300 $out .= "\n" . html::tag('ul', $attrib, $ul, html::$common_attrib); | |
| 301 | |
| 302 $this->rc->output->set_env('acl_items', $data['rights']); | |
| 303 | |
| 304 return $out; | |
| 305 } | |
| 306 | |
| 307 /** | |
| 308 * Creates ACL rights form (user part) | |
| 309 * | |
| 310 * @param array $attrib Template object attributes | |
| 311 * | |
| 312 * @return string HTML Content | |
| 313 */ | |
| 314 function templ_user($attrib) | |
| 315 { | |
| 316 // Create username input | |
| 317 $attrib['name'] = 'acluser'; | |
| 318 | |
| 319 $textfield = new html_inputfield($attrib); | |
| 320 | |
| 321 $fields['user'] = html::label(array('for' => $attrib['id']), $this->gettext('username')) | |
| 322 . ' ' . $textfield->show(); | |
| 323 | |
| 324 // Add special entries | |
| 325 if (!empty($this->specials)) { | |
| 326 foreach ($this->specials as $key) { | |
| 327 $fields[$key] = html::label(array('for' => 'id'.$key), $this->gettext($key)); | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 $this->rc->output->set_env('acl_specials', $this->specials); | |
| 332 | |
| 333 // Create list with radio buttons | |
| 334 if (count($fields) > 1) { | |
| 335 $ul = ''; | |
| 336 $radio = new html_radiobutton(array('name' => 'usertype')); | |
| 337 foreach ($fields as $key => $val) { | |
| 338 $ul .= html::tag('li', null, $radio->show($key == 'user' ? 'user' : '', | |
| 339 array('value' => $key, 'id' => 'id'.$key)) | |
| 340 . $val); | |
| 341 } | |
| 342 | |
| 343 $out = html::tag('ul', array('id' => 'usertype', 'class' => $attrib['class']), $ul, html::$common_attrib); | |
| 344 } | |
| 345 // Display text input alone | |
| 346 else { | |
| 347 $out = $fields['user']; | |
| 348 } | |
| 349 | |
| 350 return $out; | |
| 351 } | |
| 352 | |
| 353 /** | |
| 354 * Creates ACL rights table | |
| 355 * | |
| 356 * @param array $attrib Template object attributes | |
| 357 * | |
| 358 * @return string HTML Content | |
| 359 */ | |
| 360 private function list_rights($attrib=array()) | |
| 361 { | |
| 362 // Get ACL for the folder | |
| 363 $acl = $this->rc->storage->get_acl($this->mbox); | |
| 364 | |
| 365 if (!is_array($acl)) { | |
| 366 $acl = array(); | |
| 367 } | |
| 368 | |
| 369 // Keep special entries (anyone/anonymous) on top of the list | |
| 370 if (!empty($this->specials) && !empty($acl)) { | |
| 371 foreach ($this->specials as $key) { | |
| 372 if (isset($acl[$key])) { | |
| 373 $acl_special[$key] = $acl[$key]; | |
| 374 unset($acl[$key]); | |
| 375 } | |
| 376 } | |
| 377 } | |
| 378 | |
| 379 // Sort the list by username | |
| 380 uksort($acl, 'strnatcasecmp'); | |
| 381 | |
| 382 if (!empty($acl_special)) { | |
| 383 $acl = array_merge($acl_special, $acl); | |
| 384 } | |
| 385 | |
| 386 // Get supported rights and build column names | |
| 387 $supported = $this->rights_supported(); | |
| 388 | |
| 389 // give plugins the opportunity to adjust this list | |
| 390 $data = $this->rc->plugins->exec_hook('acl_rights_supported', | |
| 391 array('rights' => $supported, 'folder' => $this->mbox, 'labels' => array())); | |
| 392 $supported = $data['rights']; | |
| 393 | |
| 394 // depending on server capability either use 'te' or 'd' for deleting msgs | |
| 395 $deleteright = implode(array_intersect(str_split('ted'), $supported)); | |
| 396 | |
| 397 // Use advanced or simple (grouped) rights | |
| 398 $advanced = $this->rc->config->get('acl_advanced_mode'); | |
| 399 | |
| 400 if ($advanced) { | |
| 401 $items = array(); | |
| 402 foreach ($supported as $sup) { | |
| 403 $items[$sup] = $sup; | |
| 404 } | |
| 405 } | |
| 406 else { | |
| 407 $items = array( | |
| 408 'read' => 'lrs', | |
| 409 'write' => 'wi', | |
| 410 'delete' => $deleteright, | |
| 411 'other' => preg_replace('/[lrswi'.$deleteright.']/', '', implode($supported)), | |
| 412 ); | |
| 413 | |
| 414 // give plugins the opportunity to adjust this list | |
| 415 $data = $this->rc->plugins->exec_hook('acl_rights_simple', | |
| 416 array('rights' => $items, 'folder' => $this->mbox, 'labels' => array())); | |
| 417 $items = $data['rights']; | |
| 418 } | |
| 419 | |
| 420 // Create the table | |
| 421 $attrib['noheader'] = true; | |
| 422 $table = new html_table($attrib); | |
| 423 | |
| 424 // Create table header | |
| 425 $table->add_header('user', $this->gettext('identifier')); | |
| 426 foreach (array_keys($items) as $key) { | |
| 427 $label = $data['labels'][$key] ?: $this->gettext('shortacl'.$key); | |
| 428 $table->add_header(array('class' => 'acl'.$key, 'title' => $label), $label); | |
| 429 } | |
| 430 | |
| 431 $js_table = array(); | |
| 432 foreach ($acl as $user => $rights) { | |
| 433 if ($this->rc->storage->conn->user == $user) { | |
| 434 continue; | |
| 435 } | |
| 436 | |
| 437 // filter out virtual rights (c or d) the server may return | |
| 438 $userrights = array_intersect($rights, $supported); | |
| 439 $userid = rcube_utils::html_identifier($user); | |
| 440 | |
| 441 if (!empty($this->specials) && in_array($user, $this->specials)) { | |
| 442 $user = $this->gettext($user); | |
| 443 } | |
| 444 | |
| 445 $table->add_row(array('id' => 'rcmrow'.$userid)); | |
| 446 $table->add('user', html::a(array('id' => 'rcmlinkrow'.$userid), rcube::Q($user))); | |
| 447 | |
| 448 foreach ($items as $key => $right) { | |
| 449 $in = $this->acl_compare($userrights, $right); | |
| 450 switch ($in) { | |
| 451 case 2: $class = 'enabled'; break; | |
| 452 case 1: $class = 'partial'; break; | |
| 453 default: $class = 'disabled'; break; | |
| 454 } | |
| 455 $table->add('acl' . $key . ' ' . $class, ''); | |
| 456 } | |
| 457 | |
| 458 $js_table[$userid] = implode($userrights); | |
| 459 } | |
| 460 | |
| 461 $this->rc->output->set_env('acl', $js_table); | |
| 462 $this->rc->output->set_env('acl_advanced', $advanced); | |
| 463 | |
| 464 $out = $table->show(); | |
| 465 | |
| 466 return $out; | |
| 467 } | |
| 468 | |
| 469 /** | |
| 470 * Handler for ACL update/create action | |
| 471 */ | |
| 472 private function action_save() | |
| 473 { | |
| 474 $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true)); // UTF7-IMAP | |
| 475 $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)); | |
| 476 $acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_POST)); | |
| 477 $oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_POST)); | |
| 478 | |
| 479 $acl = array_intersect(str_split($acl), $this->rights_supported()); | |
| 480 $users = $oldid ? array($user) : explode(',', $user); | |
| 481 $result = 0; | |
| 482 | |
| 483 foreach ($users as $user) { | |
| 484 $user = trim($user); | |
| 485 $prefix = $this->rc->config->get('acl_groups') ? $this->rc->config->get('acl_group_prefix') : ''; | |
| 486 | |
| 487 if ($prefix && strpos($user, $prefix) === 0) { | |
| 488 $username = $user; | |
| 489 } | |
| 490 else if (!empty($this->specials) && in_array($user, $this->specials)) { | |
| 491 $username = $this->gettext($user); | |
| 492 } | |
| 493 else if (!empty($user)) { | |
| 494 if (!strpos($user, '@') && ($realm = $this->get_realm())) { | |
| 495 $user .= '@' . rcube_utils::idn_to_ascii(preg_replace('/^@/', '', $realm)); | |
| 496 } | |
| 497 $username = $user; | |
| 498 } | |
| 499 | |
| 500 if (!$acl || !$user || !strlen($mbox)) { | |
| 501 continue; | |
| 502 } | |
| 503 | |
| 504 $user = $this->mod_login($user); | |
| 505 $username = $this->mod_login($username); | |
| 506 | |
| 507 if ($user != $_SESSION['username'] && $username != $_SESSION['username']) { | |
| 508 if ($this->rc->storage->set_acl($mbox, $user, $acl)) { | |
| 509 $ret = array('id' => rcube_utils::html_identifier($user), | |
| 510 'username' => $username, 'acl' => implode($acl), 'old' => $oldid); | |
| 511 $this->rc->output->command('acl_update', $ret); | |
| 512 $result++; | |
| 513 } | |
| 514 } | |
| 515 } | |
| 516 | |
| 517 if ($result) { | |
| 518 $this->rc->output->show_message($oldid ? 'acl.updatesuccess' : 'acl.createsuccess', 'confirmation'); | |
| 519 } | |
| 520 else { | |
| 521 $this->rc->output->show_message($oldid ? 'acl.updateerror' : 'acl.createerror', 'error'); | |
| 522 } | |
| 523 } | |
| 524 | |
| 525 /** | |
| 526 * Handler for ACL delete action | |
| 527 */ | |
| 528 private function action_delete() | |
| 529 { | |
| 530 $mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST, true)); //UTF7-IMAP | |
| 531 $user = trim(rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST)); | |
| 532 | |
| 533 $user = explode(',', $user); | |
| 534 | |
| 535 foreach ($user as $u) { | |
| 536 $u = trim($u); | |
| 537 if ($this->rc->storage->delete_acl($mbox, $u)) { | |
| 538 $this->rc->output->command('acl_remove_row', rcube_utils::html_identifier($u)); | |
| 539 } | |
| 540 else { | |
| 541 $error = true; | |
| 542 } | |
| 543 } | |
| 544 | |
| 545 if (!$error) { | |
| 546 $this->rc->output->show_message('acl.deletesuccess', 'confirmation'); | |
| 547 } | |
| 548 else { | |
| 549 $this->rc->output->show_message('acl.deleteerror', 'error'); | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 /** | |
| 554 * Handler for ACL list update action (with display mode change) | |
| 555 */ | |
| 556 private function action_list() | |
| 557 { | |
| 558 if (in_array('acl_advanced_mode', (array)$this->rc->config->get('dont_override'))) { | |
| 559 return; | |
| 560 } | |
| 561 | |
| 562 $this->mbox = trim(rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)); // UTF7-IMAP | |
| 563 $advanced = trim(rcube_utils::get_input_value('_mode', rcube_utils::INPUT_GPC)); | |
| 564 $advanced = $advanced == 'advanced'; | |
| 565 | |
| 566 // Save state in user preferences | |
| 567 $this->rc->user->save_prefs(array('acl_advanced_mode' => $advanced)); | |
| 568 | |
| 569 $out = $this->list_rights(); | |
| 570 | |
| 571 $out = preg_replace(array('/^<table[^>]+>/', '/<\/table>$/'), '', $out); | |
| 572 | |
| 573 $this->rc->output->command('acl_list_update', $out); | |
| 574 } | |
| 575 | |
| 576 /** | |
| 577 * Creates <UL> list with descriptive access rights | |
| 578 * | |
| 579 * @param array $rights MYRIGHTS result | |
| 580 * | |
| 581 * @return string HTML content | |
| 582 */ | |
| 583 function acl2text($rights) | |
| 584 { | |
| 585 if (empty($rights)) { | |
| 586 return ''; | |
| 587 } | |
| 588 | |
| 589 $supported = $this->rights_supported(); | |
| 590 $list = array(); | |
| 591 $attrib = array( | |
| 592 'name' => 'rcmyrights', | |
| 593 'style' => 'margin:0; padding:0 15px;', | |
| 594 ); | |
| 595 | |
| 596 foreach ($supported as $right) { | |
| 597 if (in_array($right, $rights)) { | |
| 598 $list[] = html::tag('li', null, rcube::Q($this->gettext('acl' . $right))); | |
| 599 } | |
| 600 } | |
| 601 | |
| 602 if (count($list) == count($supported)) | |
| 603 return rcube::Q($this->gettext('aclfull')); | |
| 604 | |
| 605 return html::tag('ul', $attrib, implode("\n", $list)); | |
| 606 } | |
| 607 | |
| 608 /** | |
| 609 * Compares two ACLs (according to supported rights) | |
| 610 * | |
| 611 * @param array $acl1 ACL rights array (or string) | |
| 612 * @param array $acl2 ACL rights array (or string) | |
| 613 * | |
| 614 * @param int Comparison result, 2 - full match, 1 - partial match, 0 - no match | |
| 615 */ | |
| 616 function acl_compare($acl1, $acl2) | |
| 617 { | |
| 618 if (!is_array($acl1)) $acl1 = str_split($acl1); | |
| 619 if (!is_array($acl2)) $acl2 = str_split($acl2); | |
| 620 | |
| 621 $rights = $this->rights_supported(); | |
| 622 | |
| 623 $acl1 = array_intersect($acl1, $rights); | |
| 624 $acl2 = array_intersect($acl2, $rights); | |
| 625 $res = array_intersect($acl1, $acl2); | |
| 626 | |
| 627 $cnt1 = count($res); | |
| 628 $cnt2 = count($acl2); | |
| 629 | |
| 630 if ($cnt1 == $cnt2) | |
| 631 return 2; | |
| 632 else if ($cnt1) | |
| 633 return 1; | |
| 634 else | |
| 635 return 0; | |
| 636 } | |
| 637 | |
| 638 /** | |
| 639 * Get list of supported access rights (according to RIGHTS capability) | |
| 640 * | |
| 641 * @return array List of supported access rights abbreviations | |
| 642 */ | |
| 643 function rights_supported() | |
| 644 { | |
| 645 if ($this->supported !== null) { | |
| 646 return $this->supported; | |
| 647 } | |
| 648 | |
| 649 $capa = $this->rc->storage->get_capability('RIGHTS'); | |
| 650 | |
| 651 if (is_array($capa)) { | |
| 652 $rights = strtolower($capa[0]); | |
| 653 } | |
| 654 else { | |
| 655 $rights = 'cd'; | |
| 656 } | |
| 657 | |
| 658 return $this->supported = str_split('lrswi' . $rights . 'pa'); | |
| 659 } | |
| 660 | |
| 661 /** | |
| 662 * Username realm detection. | |
| 663 * | |
| 664 * @return string Username realm (domain) | |
| 665 */ | |
| 666 private function get_realm() | |
| 667 { | |
| 668 // When user enters a username without domain part, realm | |
| 669 // allows to add it to the username (and display correct username in the table) | |
| 670 | |
| 671 if (isset($_SESSION['acl_username_realm'])) { | |
| 672 return $_SESSION['acl_username_realm']; | |
| 673 } | |
| 674 | |
| 675 // find realm in username of logged user (?) | |
| 676 list($name, $domain) = explode('@', $_SESSION['username']); | |
| 677 | |
| 678 // Use (always existent) ACL entry on the INBOX for the user to determine | |
| 679 // whether or not the user ID in ACL entries need to be qualified and how | |
| 680 // they would need to be qualified. | |
| 681 if (empty($domain)) { | |
| 682 $acl = $this->rc->storage->get_acl('INBOX'); | |
| 683 if (is_array($acl)) { | |
| 684 $regexp = '/^' . preg_quote($_SESSION['username'], '/') . '@(.*)$/'; | |
| 685 foreach (array_keys($acl) as $name) { | |
| 686 if (preg_match($regexp, $name, $matches)) { | |
| 687 $domain = $matches[1]; | |
| 688 break; | |
| 689 } | |
| 690 } | |
| 691 } | |
| 692 } | |
| 693 | |
| 694 return $_SESSION['acl_username_realm'] = $domain; | |
| 695 } | |
| 696 | |
| 697 /** | |
| 698 * Initializes autocomplete LDAP backend | |
| 699 */ | |
| 700 private function init_ldap() | |
| 701 { | |
| 702 if ($this->ldap) { | |
| 703 return $this->ldap->ready; | |
| 704 } | |
| 705 | |
| 706 // get LDAP config | |
| 707 $config = $this->rc->config->get('acl_users_source'); | |
| 708 | |
| 709 if (empty($config)) { | |
| 710 return false; | |
| 711 } | |
| 712 | |
| 713 // not an array, use configured ldap_public source | |
| 714 if (!is_array($config)) { | |
| 715 $ldap_config = (array) $this->rc->config->get('ldap_public'); | |
| 716 $config = $ldap_config[$config]; | |
| 717 } | |
| 718 | |
| 719 $uid_field = $this->rc->config->get('acl_users_field', 'mail'); | |
| 720 $filter = $this->rc->config->get('acl_users_filter'); | |
| 721 | |
| 722 if (empty($uid_field) || empty($config)) { | |
| 723 return false; | |
| 724 } | |
| 725 | |
| 726 // get name attribute | |
| 727 if (!empty($config['fieldmap'])) { | |
| 728 $name_field = $config['fieldmap']['name']; | |
| 729 } | |
| 730 // ... no fieldmap, use the old method | |
| 731 if (empty($name_field)) { | |
| 732 $name_field = $config['name_field']; | |
| 733 } | |
| 734 | |
| 735 // add UID field to fieldmap, so it will be returned in a record with name | |
| 736 $config['fieldmap']['name'] = $name_field; | |
| 737 $config['fieldmap']['uid'] = $uid_field; | |
| 738 | |
| 739 // search in UID and name fields | |
| 740 // $name_field can be in a form of <field>:<modifier> (#1490591) | |
| 741 $name_field = preg_replace('/:.*$/', '', $name_field); | |
| 742 $search = array_unique(array($name_field, $uid_field)); | |
| 743 | |
| 744 $config['search_fields'] = $search; | |
| 745 $config['required_fields'] = array($uid_field); | |
| 746 | |
| 747 // set search filter | |
| 748 if ($filter) { | |
| 749 $config['filter'] = $filter; | |
| 750 } | |
| 751 | |
| 752 // disable vlv | |
| 753 $config['vlv'] = false; | |
| 754 | |
| 755 // Initialize LDAP connection | |
| 756 $this->ldap = new rcube_ldap($config, | |
| 757 $this->rc->config->get('ldap_debug'), | |
| 758 $this->rc->config->mail_domain($_SESSION['imap_host'])); | |
| 759 | |
| 760 return $this->ldap->ready; | |
| 761 } | |
| 762 | |
| 763 /** | |
| 764 * Modify user login according to 'login_lc' setting | |
| 765 */ | |
| 766 protected function mod_login($user) | |
| 767 { | |
| 768 $login_lc = $this->rc->config->get('login_lc'); | |
| 769 | |
| 770 if ($login_lc === true || $login_lc == 2) { | |
| 771 $user = mb_strtolower($user); | |
| 772 } | |
| 773 // lowercase domain name | |
| 774 else if ($login_lc && strpos($user, '@')) { | |
| 775 list($local, $domain) = explode('@', $user); | |
| 776 $user = $local . '@' . mb_strtolower($domain); | |
| 777 } | |
| 778 | |
| 779 return $user; | |
| 780 } | |
| 781 } |
