diff --git a/lib/kolab_recipient_policy.php b/lib/kolab_recipient_policy.php index d9bf1da..3ddb990 100644 --- a/lib/kolab_recipient_policy.php +++ b/lib/kolab_recipient_policy.php @@ -1,451 +1,449 @@ | +--------------------------------------------------------------------------+ | Author: Aleksander Machniak | | Author: Jeroen van Meeuwen | +--------------------------------------------------------------------------+ */ class kolab_recipient_policy { static function format() { $_args = func_get_args(); $args = array(); for ($i = 0; $i < func_num_args(); $i++) { //$args[$i] = preg_replace('/\./', '\.', $_args[$i]); $args[$i] = $_args[$i]; } return $args; } static function normalize_groupdata($groupdata) { //console("IN", $groupdata); foreach ($groupdata as $key => $value) { $groupdata[$key] = self::normalize($groupdata[$key], $groupdata['preferredlanguage']); } //console("OUT", $groupdata); return $groupdata; } static function normalize_userdata($userdata) { $keymap = array( 'sn' => 'surname', ); $zero_canon = array('ou', 'cn', 'displayname', 'mailhost'); foreach ($userdata as $key => $value) { if (in_array($key, $zero_canon)) { continue; } if (isset($keymap[$key])) { - _$key = $keymap[$key]; - } else { - _$key = $key; + $key = $keymap[$key]; } - $userdata[_$key] = self::normalize($userdata[$key], $userdata['preferredlanguage']); + $userdata[$key] = self::normalize($value, $userdata['preferredlanguage']); } return $userdata; } static function primary_mail_group($groupdata) { // Expect only a cn@domain.tld, really $groupdata = self::normalize_groupdata($groupdata); $email = ''; if (!empty($groupdata['cn'])) { $email = $groupdata['cn'] . '@' . $_SESSION['user']->get_domain(); } return self::parse_email($email); } static function primary_mail($userdata) { $userdata = self::normalize_userdata($userdata); $conf = Conf::get_instance(); if (empty($userdata['domain'])) { $userdata['domain'] = $_SESSION['user']->get_domain(); } $primary_mail = $conf->get_raw($userdata['domain'], 'primary_mail'); $primary_mail = self::apply_formats($primary_mail, $userdata); $parsed_email = self::parse_email($primary_mail); return $parsed_email; } static function secondary_mail($userdata) { $secondary_mail_addresses = array(); $functions = array( '\'%\((\w+)\)s\'\.capitalize\(\)' => 'strtoupper(substr("%(${1})s", 0, 1)) . strtolower(substr("%(${1})s", 1))', '\'%\((\w+)\)s\'\.lower\(\)' => 'strtolower("%(${1})s")', '\'%\((\w+)\)s\'\.upper\(\)' => 'strtoupper("%(${1})s")', ); $userdata = self::normalize_userdata($userdata); $conf = Conf::get_instance(); if (!array_key_exists('mail', $userdata)) { $userdata['mail'] = self::primary_mail($userdata); } if (empty($userdata['domain'])) { $userdata['domain'] = $_SESSION['user']->get_domain(); } $secondary_mail = $conf->get_raw($userdata['domain'], 'secondary_mail'); $secondary_mail = preg_replace('/^{\d:\s*/','',$secondary_mail); $secondary_mail = preg_replace('/\s*}$/','',$secondary_mail); $secondary_mail = preg_replace('/,\d+:\s*/',',',$secondary_mail); $secondary_mail = "[" . $secondary_mail . "]"; $secondary_mail = json_decode($secondary_mail, true); $orig_userdata = $userdata; foreach ($secondary_mail as $policy_rule) { foreach ($policy_rule as $format => $rule) { $userdata = $orig_userdata; $format = preg_replace('/(\{\d+\})/', '%s', $format); preg_match_all('/\'%\((\w+)\)s\'\[(\d+):(\d+)\]/', $rule, $substrings); // Update userdata array for ($x = 0; $x < count($substrings[0]); $x++) { if (array_key_exists($substrings[1][$x], $userdata)) { $userdata[$substrings[1][$x]] = substr($userdata[$substrings[1][$x]], $substrings[2][$x], $substrings[3][$x]); } else { //console("Key " . $substrings[1][$x] . " does not exist in \$userdata"); } $rule = preg_replace( '/\'%\(' . $substrings[1][$x] . '\)s\'\[' . $substrings[2][$x] . ':' . $substrings[3][$x] . '\]/', '\'%(' . $substrings[1][$x] . ')s\'', $rule ); } foreach ($functions as $match => $replace) { if (preg_match('/' . $match . '/', $rule, $strings)) { if (array_key_exists($strings[1], $userdata)) { $rule = preg_replace('/' . $match . '/', $replace, $rule); } } } $expanded = $conf->expand($rule, $userdata); eval("\$result = self::" . $expanded . ";"); eval("\$result = sprintf('" . $format . "', '" . implode("', '", array_values($result)) . "');"); if ($result = self::parse_email($result)) { // See if the equivalent is already in the 'mail' attribute value(s) if (!empty($userdata['mail'])) { if (strtolower($userdata['mail']) == strtolower($result)) { continue; } } $secondary_mail_addresses[] = $result; } } } return $secondary_mail_addresses; } static public function transliterate($mystring, $locale) { $locale_translit_map = Array( 'ru_RU' => 'cyrillic' ); $translit_map = Array( 'cyrillic' => Array( 'А' => 'A', 'а' => 'a', 'Б' => 'B', 'б' => 'b', 'В' => 'V', 'в' => 'v', 'Г' => 'G', 'г' => 'g', 'Д' => 'D', 'д' => 'd', 'Е' => 'E', 'е' => 'e', 'Ё' => 'Yo', 'ё' => 'e', 'Ж' => 'Zh', 'ж' => 'zh', 'З' => 'Z', 'з' => 'z', 'И' => 'I', 'и' => 'i', 'Й' => 'J', 'й' => 'j', 'К' => 'K', 'к' => 'k', 'Л' => 'L', 'л' => 'l', 'М' => 'M', 'м' => 'm', 'Н' => 'N', 'н' => 'n', 'О' => 'O', 'о' => 'o', 'П' => 'P', 'п' => 'p', 'Р' => 'R', 'р' => 'r', 'С' => 'S', 'с' => 's', 'Т' => 'T', 'т' => 't', 'У' => 'U', 'у' => 'u', 'Ф' => 'F', 'ф' => 'f', 'Х' => 'Kh', 'х' => 'kh', 'Ц' => 'Tc', 'ц' => 'tc', 'Ч' => 'Ch', 'ч' => 'ch', 'Ш' => 'Sh', 'ш' => 'sh', 'Щ' => 'Shch', 'щ' => 'shch', 'Ъ' => '', 'ъ' => '', 'Ы' => 'Y', 'ы' => 'y', 'Ь' => '', 'ь' => '', 'Э' => 'E', 'э' => 'e', 'Ю' => 'Yu', 'ю' => 'yu', 'Я' => 'Ya', 'я' => 'ya', ), ); if ($translit = $translit_map[$locale_translit_map[$locale]]) { $mystring = strtr($mystring, $translit); } return $mystring; } static public function uid($userdata) { $conf = Conf::get_instance(); if (empty($userdata['domain'])) { $userdata['domain'] = $_SESSION['user']->get_domain(); } $policy_uid = $conf->get_raw($userdata['domain'], 'policy_uid'); if (empty($policy_uid)) { $policy_uid = "%(surname)s.lower()"; } $functions = array( '\'*(\w+)\'*\.capitalize\(\).*' => 'strtoupper(substr("${1}", 0, 1)) . strtolower(substr("${1}", 1))', '\'*(.*)\'*\.lower\(\).*' => 'strtolower("${1}")', '\'*(\w+)\'*\.upper\(\).*' => 'strtoupper("${1}")', ); $policy_uid = preg_replace('/(\{\d+\})/', '%s', $policy_uid); $policy_uid = self::apply_formats($policy_uid, $userdata); foreach ($functions as $match => $replace) { while (preg_match('/' . $match . '/', $policy_uid, $strings)) { $policy_uid = preg_replace('/' . $match . '/', $replace, $policy_uid); } } Log::trace("kolab_recipient_policy::" . __LINE__ . " \$policy_uid: " . var_export($policy_uid, TRUE)); $formatted_policy_uid = explode(":", $policy_uid); if (is_array($formatted_policy_uid) && count($formatted_policy_uid) == 2) { eval("\$policy_uid = sprintf(" . $formatted_policy_uid[0] . ", " . $formatted_policy_uid[1] . ");"); } elseif (preg_match('/\(/', $policy_uid) && preg_match('/\)/', $policy_uid)) { eval("\$policy_uid = " . $policy_uid . ";"); } else { eval("\$policy_uid = '" . $policy_uid . "';"); } return $policy_uid; } /** * Make sure email address is valid, if not return empty string */ static private function parse_email($email) { $email = strtolower($email); $email_parts = explode('@', $email); $email_parts = array_filter($email_parts); // do some simple checks here if (count($email_parts) < 2) { return ''; } // trim dots, it's most likely case $email_parts[0] = trim($email_parts[0], '.'); // from PEAR::Validate $regexp = '&^(?: ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322) $&xi'; if (!preg_match($regexp, $email_parts[0])) { return ''; } return $email_parts[0] . '@' . $email_parts[1]; } /** * Implements string replacement according to defined format */ static private function apply_formats($subject, $userdata) { preg_match_all('/%\((\w+)\)s/', $subject, $substrings); // Update userdata array for ($x = 0; $x < count($substrings[0]); $x++) { if (array_key_exists($substrings[1][$x], $userdata)) { if (!empty($substrings[2][$x])) { if (!empty($substrings[3][$x])) { $subject = preg_replace( '/%\(' . $substrings[1][$x]. '\)s/', substr($userdata[$substrings[1][$x]], $substrings[2][$x], $substrings[3][$x]), $subject ); } else { $subject = preg_replace( '/%\(' . $substrings[1][$x]. '\)s/', substr($userdata[$substrings[1][$x]], $substrings[2][$x]), $subject ); } } else if (!empty($substrings[3][$x])) { $subject = preg_replace( '/%\(' . $substrings[1][$x]. '\)s/', substr($userdata[$substrings[1][$x]], 0, $substrings[3][$x]), $subject ); } else { $subject = preg_replace( '/%\(' . $substrings[1][$x]. '\)s/', $userdata[$substrings[1][$x]], $subject ); } } } preg_match_all('/.*\'(.*)\'\[(\d+):(\d+)\].*/U', $subject, $substrings); for ($x = 0; $x < count($substrings[0]); $x++) { if (!empty($substrings[2][$x])) { $start = $substrings[2][$x]; } else { $start = 0; } if (!empty($substrings[3][$x])) { $end = $substrings[3][$x]; } else { $end = 0; } $subject = preg_replace( "/'" . $substrings[1][$x] . "'\[" . $substrings[2][$x] . ':' . $substrings[3][$x] . "\]/", substr($substrings[1][$x], $start, $end), $subject ); } return $subject; } public static function normalize($str, $locale = null) { if (empty($locale)) { $conf = Conf::get_instance(); $locale = $conf->get('default_locale'); } if (!empty($locale)) { $old_locale = setlocale(LC_CTYPE, $locale.'.utf8', $locale.'.UTF-8', $locale); } if (is_string($str)) { $result = iconv('UTF-8', 'ASCII//TRANSLIT', $str); if (strpos($result, '?')) { $result = self::transliterate($str, $locale); } $str = preg_replace('/[^a-z0-9-_]/i', '', $result); } if ($old_locale && $old_locale != $locale) { setlocale(LC_CTYPE, $old_locale); } return $str; } }