⚝
One Hat Cyber Team
⚝
Your IP:
216.73.217.4
Server IP:
41.128.143.86
Server:
Linux host.raqmix.cloud 6.8.0-1025-azure #30~22.04.1-Ubuntu SMP Wed Mar 12 15:28:20 UTC 2025 x86_64
Server Software:
Apache
PHP Version:
8.3.23
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
proc
/
self
/
root
/
usr
/
share
/
psa-horde
/
turba
/
lib
/
Edit File: Turba.php
<?php /** * Copyright 2000-2017 Horde LLC (http://www.horde.org/) * * See the enclosed file LICENSE for license information (ASL). If you did * did not receive this file, see http://www.horde.org/licenses/apache. * * @category Horde * @copyright 2000-2017 Horde LLC * @license http://www.horde.org/licenses/apache ASL * @package Turba */ /** * Turba Base Class. * * @author Chuck Hagenbuch <chuck@horde.org> * @author Jon Parise <jon@horde.org> * @category Horde * @copyright 2000-2017 Horde LLC * @license http://www.horde.org/licenses/apache ASL * @package Turba */ class Turba { /** * The virtual path to use for VFS data. */ const VFS_PATH = '.horde/turba/documents'; /** * The current source. * * @var string */ static public $source; /** * Cached data. * * @var array */ static protected $_cache = array(); /** * Returns the source entries from config/backends.php that have been * configured as available sources in the main Turba configuration. * * @return array List of available sources. * @throws Horde_Exception */ static public function availableSources() { global $registry; $s = $registry->loadConfigFile('backends.php', 'cfgSources', 'turba')->config['cfgSources']; $sources = array(); foreach ($s as $key => $source) { if (empty($source['disabled'])) { $sources[$key] = $source; } } return $sources; } /** * Get all the address books the user has the requested permissions to and * return them in the user's preferred order. * * @param integer $permission The Horde_Perms::* constant to filter on. * @param array $options Any additional options. * * @return array The filtered, ordered $cfgSources entries. */ static public function getAddressBooks($permission = Horde_Perms::READ, array $options = array()) { return self::permissionsFilter( $GLOBALS['cfgSources'], $permission, $options ); } /** * Returns the current user's default address book. * * @return string The default address book name. */ static public function getDefaultAddressbook() { /* In case of shares select first user owned address book as default */ if (!empty($_SESSION['turba']['has_share'])) { try { $owned_shares = self::listShares(true); if (count($owned_shares)) { return key($owned_shares); } } catch (Exception $e) {} } reset($GLOBALS['cfgSources']); return key($GLOBALS['cfgSources']); } /** * Returns the sort order selected by the user. * * @return array TODO */ static public function getPreferredSortOrder() { return @unserialize($GLOBALS['prefs']->getValue('sortorder')); } /** * Saves the sort order to the preferences backend. * * @param Horde_Variables $vars Variables object. * @param string $source Source. */ static public function setPreferredSortOrder(Horde_Variables $vars, $source) { if (!strlen($sortby = $vars->get('sortby'))) { return; } $sources = self::getColumns(); $columns = isset($sources[$source]) ? $sources[$source] : array(); $column_name = self::getColumnName($sortby, $columns); $append = true; $ascending = ($vars->get('sortdir') == 0); if ($vars->get('sortadd')) { $sortorder = self::getPreferredSortOrder(); foreach ($sortorder as $i => $elt) { if ($elt['field'] == $column_name) { $sortorder[$i]['ascending'] = $ascending; $append = false; } } } else { $sortorder = array(); } if ($append) { $sortorder[] = array( 'ascending' => $ascending, 'field' => $column_name ); } $GLOBALS['prefs']->setValue('sortorder', serialize($sortorder)); } /** * Retrieves a column's field name. * * @param integer $i TODO * @param array $columns TODO * * @return string TODO */ static public function getColumnName($i, $columns) { return (($i == 0) || !isset($columns[$i - 1])) ? 'name' : $columns[$i - 1]; } /** * TODO */ static public function getColumns() { $columns = array(); $lines = explode("\n", $GLOBALS['prefs']->getValue('columns')); foreach ($lines as $line) { $line = trim($line); if ($line) { $cols = explode("\t", $line); if (count($cols) > 1) { $source = array_splice($cols, 0, 1); $columns[$source[0]] = array(); foreach ($cols as $col) { if ($col == '__tags' || isset($GLOBALS['cfgSources'][$source[0]]['map'][$col])) { $columns[$source[0]][] = $col; } } } } } return $columns; } /** * Builds and cleans up a composite field. * * @param string $format The sprintf field format. * @param array $fields The fields that compose the composite field. * * @return string The formatted composite field. */ static public function formatCompositeField($format, $fields) { return preg_replace('/ +/', ' ', trim(vsprintf($format, $fields), " \t\n\r\0\x0B,")); } /** * Returns a best guess at the lastname in a string. * * @param string $name String contain the full name. * * @return string String containing the last name. */ static public function guessLastname($name) { $name = trim(preg_replace('|\s|', ' ', $name)); if (!empty($name)) { /* Assume that last names are always before any commas. */ if (is_int(strpos($name, ','))) { $name = Horde_String::substr($name, 0, strpos($name, ',')); } /* Take out anything in parentheses. */ $name = trim(preg_replace('|\(.*\)|', '', $name)); $namelist = explode(' ', $name); $name = $namelist[($nameindex = (count($namelist) - 1))]; while (!empty($name) && (($nlength = Horde_String::length($name)) < 5) && strspn($name[($nlength - 1)], '.:-') && !empty($namelist[($nameindex - 1)])) { $name = $namelist[--$nameindex]; } } return strlen($name) ? $name : null; } /** * Formats the name according to the user's preference. * * If the format is 'none', the full name with all parts is returned. If * the format is 'last_first' or 'first_last', only the first name and * last name are returned. * * @param Turba_Object $ob The object to get a name from. * @param string $name_format The formatting. One of 'none', 'last_first' * or 'first_last'. Defaults to the user * preference. * * @return string The formatted name, either "Firstname Lastname" * or "Lastname, Firstname" depending on $name_format or * the user's preference. */ static public function formatName(Turba_Object $ob, $name_format = null) { if (!$name_format) { if (!isset(self::$_cache['defaultFormat'])) { self::$_cache['defaultFormat'] = $GLOBALS['prefs']->getValue('name_format'); } $name_format = self::$_cache['defaultFormat']; } /* If no formatting, return original name. */ if (!in_array($name_format, array('first_last', 'last_first'))) { return $ob->getValue('name'); } /* See if we have the name fields split out explicitly. */ if ($ob->hasValue('firstname') && $ob->hasValue('lastname')) { return ($name_format == 'last_first') ? $ob->getValue('lastname') . ', ' . $ob->getValue('firstname') : $ob->getValue('firstname') . ' ' . $ob->getValue('lastname'); } /* One field, we'll have to guess. */ $name = $ob->getValue('name'); $lastname = self::guessLastname($name); if (($name_format == 'last_first') && !is_int(strpos($name, ',')) && (Horde_String::length($name) > Horde_String::length($lastname))) { return $lastname . ', ' . preg_replace('/\s+' . preg_quote($lastname, '/') . '/', '', $name); } if (($name_format == 'first_last') && is_int(strpos($name, ',')) && (Horde_String::length($name) > Horde_String::length($lastname))) { return preg_replace('/' . preg_quote($lastname, '/') . ',\s*/', '', $name) . ' ' . $lastname; } return $name; } /** * TODO * * @param mixed $data Either a single email address or an array of email * addresses to format. * @param string $name The personal name phrase. * * @return mixed Either the formatted address or an array of formatted * addresses. */ static public function formatEmailAddresses($data, $name) { if (!isset(self::$_cache['useRegistry'])) { self::$_cache['useRegistry'] = $GLOBALS['registry']->hasMethod('mail/batchCompose'); } $out = array(); $rfc822 = $GLOBALS['injector']->getInstance('Horde_Mail_Rfc822'); if (!is_array($data)) { $data = array($data); } foreach ($data as $email_vals) { foreach ($rfc822->parseAddressList($email_vals) as $ob) { $addr = strval($ob); $tmp = null; if (self::$_cache['useRegistry']) { try { $tmp = $GLOBALS['registry']->call('mail/batchCompose', array(array($addr))); } catch (Horde_Exception $e) { self::$_cache['useRegistry'] = false; } } $tmp = empty($tmp) ? 'mailto:' . urlencode($addr) : reset($tmp); $out[] = Horde::link($tmp) . htmlspecialchars($addr) . '</a>'; } } return implode(', ', $out); } /** * Returns the real name, if available, of a user. * * @param string $uid The uid of the name to return. * * @return string The user's full, real name. */ static public function getUserName($uid) { if (!isset(self::$_cache['names'])) { self::$_cache['names'] = array(); } if (!isset(self::$_cache['names'][$uid])) { $ident = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($uid); $ident->setDefault($ident->getDefault()); $name = $ident->getValue('fullname'); self::$_cache['names'][$uid] = empty($name) ? $uid : $name; } return self::$_cache['names'][$uid]; } /** * Gets extended permissions on an address book. * * @param Turba_Driver $addressBook The address book to get extended * permissions for. * @param string $permission What extended permission to get. * * @return mixed The requested extended permissions value, or true if it * doesn't exist. */ static public function getExtendedPermission(Turba_Driver $addressBook, $permission) { // We want to check the base source as extended permissions // are enforced per backend, not per share. $key = $addressBook->getName() . ':' . $permission; $perms = $GLOBALS['injector']->getInstance('Horde_Perms'); if (!$perms->exists('turba:sources:' . $key)) { return true; } $allowed = $perms->getPermissions('turba:sources:' . $key, $GLOBALS['registry']->getAuth()); if (is_array($allowed)) { switch ($permission) { case 'max_contacts': $allowed = max($allowed); break; } } return $allowed; } /** * Filters sources based on permissions. * * @param array $in The source list we want filtered. * @param integer $permission The Horde_Perms::* constant we will filter * on. * @param array $options Additional options: * - require_add: (boolean) Only return sources * that can be added to. * * @return array The filtered data. */ static public function permissionsFilter(array $in, $permission = Horde_Perms::READ, array $options = array()) { $factory = $GLOBALS['injector']->getInstance('Turba_Factory_Driver'); $out = array(); foreach ($in as $sourceId => $source) { try { $driver = $factory->createFromConfig($source, $sourceId); if ($driver->hasPermission($permission) && (empty($options['require_add']) || $driver->canAdd())) { $out[$sourceId] = $source; } } catch (Turba_Exception $e) { Horde::log($e, 'ERR'); } } return $out; } /** * Replaces all share-enabled sources in a source list with all shares * from this source that the current user has access to. * * This will only sync shares that are unique to Horde (such as a SQL or * Kolab sources). Any backend that supports ACLs or similar mechanism * should be configured from within backends.local.php or via Horde's * share_* hooks. * * @param array $sources The default $cfgSources array. * @param boolean $owner Only return shares that the current user owns? * @param array $options An array of options: * - shares: Use this list of provided shares. Default is to get the * list from the share system using the current user. * - auth_user: Use this as the authenticated user name. * * @return array The $cfgSources array. */ public static function getConfigFromShares(array $sources, $owner = false, $options = array()) { global $notification, $registry, $conf, $injector, $prefs; if (empty($options['shares'])) { try { $shares = self::listShares($owner); } catch (Horde_Share_Exception $e) { // Notify the user if we failed, but still return the $cfgSource // array. $notification->push($e, 'horde.error'); return $sources; } } else { $shares = $options['shares']; } /* See if any of our sources are configured to handle all otherwise * unassigned Horde_Share objects. */ $all_shares = null; foreach ($sources as $key => $cfg) { if (!empty($cfg['all_shares'])) { // Indicate the source handler that catches unassigned shares. $all_shares = $key; } } if (empty($options['auth_user'])) { $auth_user = $registry->getAuth(); } else { $auth_user = $options['auth_user']; } $sortedSources = $vbooks = array(); $personal = false; foreach ($shares as $name => &$share) { if (isset($sources[$name])) { continue; } $personal |= ($share->get('owner') == $auth_user); $params = @unserialize($share->get('params')); if (empty($params['source']) && !empty($all_shares)) { $params['source'] = $all_shares; } if (isset($params['type']) && $params['type'] == 'vbook') { // We load vbooks last in case they're based on other shares. $params['share'] = $share; $vbooks[$name] = $params; } elseif (!empty($params['source']) && !empty($sources[$params['source']]['use_shares'])) { if (empty($params['name'])) { $params['name'] = $name; $share->set('params', serialize($params)); try { $share->save(); } catch (Horde_Share_Exception $e) { Horde::log($e, 'ERR'); } } $info = $sources[$params['source']]; $info['params']['config'] = $sources[$params['source']]; $info['params']['config']['params']['share'] = $share; $info['params']['config']['params']['name'] = $params['name']; $info['title'] = $share->get('name'); if ($share->get('owner') != $auth_user) { $info['title'] .= ' [' . $registry->convertUsername($share->get('owner'), false) . ']'; } $info['type'] = 'share'; $info['use_shares'] = false; $sortedSources[$params['source']][$name] = $info; } } // Check for the user's default share and built new source list. $newSources = array(); foreach (array_keys($sources) as $source) { if (empty($sources[$source]['use_shares'])) { $newSources[$source] = $sources[$source]; continue; } if (isset($sortedSources[$source])) { $newSources = array_merge($newSources, $sortedSources[$source]); } if (!empty($conf['share']['auto_create']) && $auth_user && !$personal) { // User's default share is missing. try { $driver = $injector ->getInstance('Turba_Factory_Driver') ->create($source); } catch (Turba_Exception $e) { $notification->push($e->getMessage(), 'horde.error'); continue; } $sourceKey = strval(new Horde_Support_Randomid()); try { $share = $driver->createShare( $sourceKey, array( 'params' => array( 'source' => $source, 'default' => true, 'name' => $auth_user ) ) ); $source_config = $sources[$source]; $source_config['params']['share'] = $share; $newSources[$sourceKey] = $source_config; $personal = true; $prefs->setValue('default_dir', $share->getName()); } catch (Horde_Share_Exception $e) { Horde::log($e, 'ERR'); } } } // Add vbooks now that all available address books are loaded. foreach ($vbooks as $name => $params) { if (isset($newSources[$params['source']])) { $newSources[$name] = array( 'title' => $shares[$name]->get('name'), 'type' => 'vbook', 'params' => $params, 'export' => true, 'browse' => true, 'map' => $newSources[$params['source']]['map'], 'search' => $newSources[$params['source']]['search'], 'strict' => $newSources[$params['source']]['strict'], 'use_shares' => false, ); } else { $notification->push(sprintf( _("Removing the virtual address book \"%s\" because the parent source has disappeared."), $shares[$name]->get('name')), 'horde.message' ); try { $injector->getInstance('Turba_Shares')->removeShare($shares[$name]); } catch (Horde_Share_Exception $e) { Horde::log($e, 'ERR'); } } } return $newSources; } /** * Retrieve a new source config entry based on a Turba share. * * @param Horde_Share_Object object The share to base config on. * * @return array The $cfgSource entry for this share source. */ public static function getSourceFromShare(Horde_Share_Object $share) { // Require a fresh config file. $cfgSources = self::availableSources(); $params = @unserialize($share->get('params')); $newConfig = $cfgSources[$params['source']]; $newConfig['params']['config'] = $cfgSources[$params['source']]; $newConfig['params']['config']['params']['share'] = $share; $newConfig['params']['config']['params']['name'] = $params['name']; $newConfig['title'] = $share->get('name'); $newConfig['type'] = 'share'; $newConfig['use_shares'] = false; return $newConfig; } /** * Returns all shares the current user has specified permissions to. * * @param boolean $owneronly Only return address books owned by the user? * Defaults to false. * @param integer $permission Permissions to filter by. * * @return array Shares the user has the requested permissions to. */ static public function listShares($owneronly = false, $permission = Horde_Perms::READ) { if (!$GLOBALS['session']->get('turba', 'has_share') || ($owneronly && !$GLOBALS['registry']->getAuth())) { return array(); } try { return $GLOBALS['injector']->getInstance('Turba_Shares')->listShares( $GLOBALS['registry']->getAuth(), array( 'attributes' => $owneronly ? $GLOBALS['registry']->getAuth() : null, 'perm' => $permission ) ); } catch (Horde_Share_Exception $e) { Horde::log($e, 'ERR'); return array(); } } /** * Create a new Turba share. * * @param string $share_name The id for the new share. * @param array $params Parameters for the new share. * * @return Horde_Share The new share object. * @throws Turba_Exception */ static public function createShare($share_name, $params) { if (isset($params['name'])) { $name = $params['name']; unset($params['name']); } else { /* Sensible default for empty display names */ $name = sprintf(_("Address book of %s"), $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create()->getName()); } /* Generate the new share. */ try { $turba_shares = $GLOBALS['injector']->getInstance('Turba_Shares'); $share = $turba_shares->newShare($GLOBALS['registry']->getAuth(), $share_name, $name); /* Now any other params. */ foreach ($params as $key => $value) { if (!is_scalar($value)) { $value = serialize($value); } $share->set($key, $value); } $turba_shares->addShare($share); $share->save(); } catch (Horde_Share_Exception $e) { Horde::log($e, 'ERR'); throw new Turba_Exception($e); } return $share; } /** * Add browse.js javascript to page. */ static public function addBrowseJs() { global $page_output; $page_output->addScriptFile('browse.js'); $page_output->addInlineJsVars(array( 'TurbaBrowse.confirmdelete' => _("Are you sure that you want to delete %s?"), 'TurbaBrowse.contact1' => _("You must select at least one contact first."), 'TurbaBrowse.contact2' => _("You must select a target contact list."), 'TurbaBrowse.contact3' => _("Please name the new contact list:"), 'TurbaBrowse.copymove' => _("You must select a target address book."), 'TurbaBrowse.submit' => _("Are you sure that you want to delete the selected contacts?") )); } /** * Return an array of all available attributes of type 'email'. Optionally, * ensure the field is defined in the specified $source. * * @param $source string An optional source identifier. * @param $searchable boolean If true, and $source is provided, ensure that * the email field is a configured searchable * field. * * @return array An array of email fields. * @since 4.2.9 */ public static function getAvailableEmailFields($source = null, $searchable = true) { global $attributes, $injector, $cfgSources; if (!empty($source)) { $driver = $injector->getInstance('Turba_Factory_Driver') ->create($source); } $emailFields = array(); foreach ($attributes as $field => $data) { if ($data['type'] == 'email') { if (empty($source) || (!empty($source) && in_array($field, array_keys($driver->map)) && (!$searchable || ($searchable && in_array($field, $cfgSources[$source]['search']))))) $emailFields[] = $field; } } return $emailFields; } }
Simpan