| | |
| | | CHANGELOG Roundcube Webmail |
| | | =========================== |
| | | |
| | | - Support 'abort' and 'result' response in 'preferences_save' hook, add error handling |
| | | - Fix bug where some content would cause hang on html2text conversion (#1487863) |
| | | - Improve space-stuffing handling in format=flowed messages (#1487861) |
| | | - Fix bug where some dates would produce SQL error in MySQL (#1487856) |
| | | - Added workaround for some IMAP server with broken STATUS response (#1487859) |
| | | - Fix bug where default_charset was not used for text messages (#1487836) |
| | | - Stateless request tokens. No keep-alive necessary on login page (#1487829) |
| | | - PEAR::Net_SMTP 1.5.1 |
| | | - Force names of unique constraints in PostgreSQL DDL |
| | |
| | | $labels['vacationreason'] = 'Treść (przyczyna nieobecności):'; |
| | | $labels['filterset'] = 'Zbiór filtrów'; |
| | | $labels['filtersetadd'] = 'Dodaj zbiór filtrów'; |
| | | $labels['filtersetdel'] = 'Usuń bierzący zbiór filtrów'; |
| | | $labels['filtersetact'] = 'Aktywuj bierzący zbiór filtrów'; |
| | | $labels['filtersetdeact'] = 'Deaktywuj bierzący zbiór filtrów'; |
| | | $labels['filtersetget'] = 'Pobierz bierzący zbiór filtrów w formacie tekstowym'; |
| | | $labels['filtersetdel'] = 'Usuń bieżący zbiór filtrów'; |
| | | $labels['filtersetact'] = 'Aktywuj bieżący zbiór filtrów'; |
| | | $labels['filtersetdeact'] = 'Deaktywuj bieżący zbiór filtrów'; |
| | | $labels['filtersetget'] = 'Pobierz bieżący zbiór filtrów w formacie tekstowym'; |
| | | $labels['filterdef'] = 'Definicja filtra'; |
| | | $labels['filtersetname'] = 'Nazwa zbioru'; |
| | | $labels['newfilterset'] = 'Nowy zbiór filtrów'; |
| | |
| | | * @param rcube_message_part $o_part Part object created by get_structure() |
| | | * @param mixed $print True to print part, ressource to write part contents in |
| | | * @param resource $fp File pointer to save the message part |
| | | * @param boolean $skip_charset_conv Disables charset conversion |
| | | * |
| | | * @return string Message/part body if not printed |
| | | */ |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL) |
| | | function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL, $fp=NULL, $skip_charset_conv=false) |
| | | { |
| | | // get part encoding if not provided |
| | | if (!is_object($o_part)) { |
| | |
| | | return true; |
| | | } |
| | | |
| | | // convert charset (if text or message part) and part's charset is specified |
| | | if ($body && $o_part->charset |
| | | && preg_match('/^(text|message)$/', $o_part->ctype_primary) |
| | | // convert charset (if text or message part) |
| | | if ($body && !$skip_charset_conv && |
| | | preg_match('/^(text|message)$/', $o_part->ctype_primary) |
| | | ) { |
| | | if (!$o_part->charset || strtoupper($o_part->charset) == 'US-ASCII') { |
| | | $o_part->charset = $this->default_charset; |
| | | } |
| | | $body = rcube_charset_convert($body, $o_part->charset); |
| | | } |
| | | |
| | |
| | | |
| | | list($mbox, $items) = $this->tokenizeResponse($response, 2); |
| | | |
| | | // Fix for #1487859. Some buggy server returns not quoted |
| | | // folder name with spaces. Let's try to handle this situation |
| | | if (!is_array($items) && ($pos = strpos($response, '(')) !== false) { |
| | | $response = substr($response, $pos); |
| | | $items = $this->tokenizeResponse($response, 1); |
| | | if (!is_array($items)) { |
| | | return $result; |
| | | } |
| | | } |
| | | |
| | | for ($i=0, $len=count($items); $i<$len; $i += 2) { |
| | | $result[$items[$i]] = (int) $items[$i+1]; |
| | | } |
| | |
| | | if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/sU', $line, $matches)) { |
| | | $str = $matches[1]; |
| | | |
| | | // swap parents with quotes, then explode |
| | | $str = preg_replace('/[()]/', '"', $str); |
| | | $a = rcube_explode_quoted_string(' ', $str); |
| | | |
| | | // did we get the right number of replies? |
| | | $parts_count = count($a); |
| | | if ($parts_count>=6) { |
| | | for ($i=0; $i<$parts_count; $i=$i+2) { |
| | | if ($a[$i] == 'UID') { |
| | | $result[$id]->uid = intval($a[$i+1]); |
| | | while (list($name, $value) = $this->tokenizeResponse($str, 2)) { |
| | | if ($name == 'UID') { |
| | | $result[$id]->uid = intval($value); |
| | | } |
| | | else if ($a[$i] == 'RFC822.SIZE') { |
| | | $result[$id]->size = intval($a[$i+1]); |
| | | else if ($name == 'RFC822.SIZE') { |
| | | $result[$id]->size = intval($value); |
| | | } |
| | | else if ($a[$i] == 'INTERNALDATE') { |
| | | $time_str = $a[$i+1]; |
| | | else if ($name == 'INTERNALDATE') { |
| | | $result[$id]->internaldate = $value; |
| | | $result[$id]->date = $value; |
| | | $result[$id]->timestamp = $this->StrToTime($value); |
| | | } |
| | | else if ($a[$i] == 'FLAGS') { |
| | | $flags_str = $a[$i+1]; |
| | | else if ($name == 'FLAGS') { |
| | | $flags_a = $value; |
| | | } |
| | | } |
| | | |
| | | $time_str = str_replace('"', '', $time_str); |
| | | |
| | | // if time is gmt... |
| | | $time_str = str_replace('GMT','+0000',$time_str); |
| | | |
| | | $result[$id]->internaldate = $time_str; |
| | | $result[$id]->timestamp = $this->StrToTime($time_str); |
| | | $result[$id]->date = $time_str; |
| | | } |
| | | |
| | | // BODYSTRUCTURE |
| | |
| | | |
| | | // handle FLAGS reply after headers (AOL, Zimbra?) |
| | | if (preg_match('/\s+FLAGS \((.*)\)\)$/', $line, $matches)) { |
| | | $flags_str = $matches[1]; |
| | | $flags_a = $this->tokenizeResponse($matches[1]); |
| | | break; |
| | | } |
| | | |
| | |
| | | |
| | | // create array with header field:data |
| | | while (list($lines_key, $str) = each($lines)) { |
| | | list($field, $string) = $this->splitHeaderLine($str); |
| | | list($field, $string) = explode(':', $str, 2); |
| | | |
| | | $field = strtolower($field); |
| | | $string = preg_replace('/\n\s*/', ' ', $string); |
| | | $string = preg_replace('/\n[\t\s]*/', ' ', trim($string)); |
| | | |
| | | switch ($field) { |
| | | case 'date'; |
| | |
| | | } |
| | | |
| | | // process flags |
| | | if (!empty($flags_str)) { |
| | | $flags_str = preg_replace('/[\\\"]/', '', $flags_str); |
| | | $flags_a = explode(' ', $flags_str); |
| | | |
| | | if (is_array($flags_a)) { |
| | | if (!empty($flags_a)) { |
| | | foreach($flags_a as $flag) { |
| | | $flag = strtoupper($flag); |
| | | if ($flag == 'SEEN') { |
| | | $flag = str_replace('\\', '', $flag); |
| | | $result[$id]->flags[] = $flag; |
| | | |
| | | switch (strtoupper($flag)) { |
| | | case 'SEEN': |
| | | $result[$id]->seen = true; |
| | | } else if ($flag == 'DELETED') { |
| | | break; |
| | | case 'DELETED': |
| | | $result[$id]->deleted = true; |
| | | } else if ($flag == 'RECENT') { |
| | | $result[$id]->recent = true; |
| | | } else if ($flag == 'ANSWERED') { |
| | | break; |
| | | case 'ANSWERED': |
| | | $result[$id]->answered = true; |
| | | } else if ($flag == '$FORWARDED') { |
| | | break; |
| | | case '$FORWARDED': |
| | | $result[$id]->forwarded = true; |
| | | } else if ($flag == 'DRAFT') { |
| | | $result[$id]->is_draft = true; |
| | | } else if ($flag == '$MDNSENT') { |
| | | break; |
| | | case '$MDNSENT': |
| | | $result[$id]->mdn_sent = true; |
| | | } else if ($flag == 'FLAGGED') { |
| | | break; |
| | | case 'FLAGGED': |
| | | $result[$id]->flagged = true; |
| | | break; |
| | | } |
| | | } |
| | | $result[$id]->flags = $flags_a; |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | // support non-standard "GMTXXXX" literal |
| | | $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); |
| | | |
| | | // if date parsing fails, we have a date in non-rfc format. |
| | | // remove token from the end and try again |
| | | while ((($ts = @strtotime($date))===false) || ($ts < 0)) { |
| | | while (($ts = intval(@strtotime($date))) <= 0) { |
| | | $d = explode(' ', $date); |
| | | array_pop($d); |
| | | if (!$d) { |
| | |
| | | $ts = (int) $ts; |
| | | |
| | | return $ts < 0 ? 0 : $ts; |
| | | } |
| | | |
| | | private function splitHeaderLine($string) |
| | | { |
| | | $pos = strpos($string, ':'); |
| | | if ($pos>0) { |
| | | $res[0] = substr($string, 0, $pos); |
| | | $res[1] = trim(substr($string, $pos+1)); |
| | | return $res; |
| | | } |
| | | return $string; |
| | | } |
| | | |
| | | private function parseCapability($str, $trusted=false) |
| | |
| | | */ |
| | | function fromunixtime($timestamp) |
| | | { |
| | | switch($this->db_provider) { |
| | | case 'mysqli': |
| | | case 'mysql': |
| | | case 'sqlite': |
| | | return sprintf("FROM_UNIXTIME(%d)", $timestamp); |
| | | |
| | | default: |
| | | return date("'Y-m-d H:i:s'", $timestamp); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | $line = $prefix . rc_wordwrap($line, $length - $level - 2, " \r\n$prefix "); |
| | | } |
| | | else if ($line) { |
| | | $line = ' ' . rc_wordwrap(rtrim($line), $length - 2, " \r\n "); |
| | | $line = rc_wordwrap(rtrim($line), $length - 2, " \r\n"); |
| | | // space-stuffing |
| | | $line = preg_replace('/(^|\r\n)(From| |>)/', '\\1 \\2', $line); |
| | | } |
| | | |
| | | $text[$idx] = $line; |
| | |
| | | this.compose_field_hash = function(save) |
| | | { |
| | | // check input fields |
| | | var value_to = $("[name='_to']").val(); |
| | | var value_cc = $("[name='_cc']").val(); |
| | | var value_bcc = $("[name='_bcc']").val(); |
| | | var value_subject = $("[name='_subject']").val(); |
| | | var str = ''; |
| | | var ed, str = '', |
| | | value_to = $("[name='_to']").val(), |
| | | value_cc = $("[name='_cc']").val(), |
| | | value_bcc = $("[name='_bcc']").val(), |
| | | value_subject = $("[name='_subject']").val(); |
| | | |
| | | if (value_to) |
| | | str += value_to+':'; |
| | |
| | | if (value_subject) |
| | | str += value_subject+':'; |
| | | |
| | | var editor = tinyMCE.get(this.env.composebody); |
| | | if (editor) |
| | | str += editor.getContent(); |
| | | if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) |
| | | str += ed.getContent(); |
| | | else |
| | | str += $("[name='_message']").val(); |
| | | |
| | |
| | | var current_li, target_li; |
| | | |
| | | if ((current_li = this.get_folder_li(old, prefix))) { |
| | | $(current_li).removeClass('selected').removeClass('unfocused'); |
| | | $(current_li).removeClass('selected').addClass('unfocused'); |
| | | } |
| | | if ((target_li = this.get_folder_li(name, prefix))) { |
| | | $(target_li).removeClass('unfocused').addClass('selected'); |
| | |
| | | */ |
| | | function _convert_pre(&$text) |
| | | { |
| | | // get the content of PRE element |
| | | while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) { |
| | | $result = preg_replace($this->pre_search, $this->pre_replace, $matches[1]); |
| | | $text = preg_replace('/<pre[^>]*>.*<\/pre>/ismU', '<div><br>' . $result . '<br></div>', $text, 1); |
| | | // convert the content |
| | | $this->pre_content = sprintf('<div><br>%s<br></div>', |
| | | preg_replace($this->pre_search, $this->pre_replace, $matches[1])); |
| | | // replace the content (use callback because content can contain $0 variable) |
| | | $text = preg_replace_callback('/<pre[^>]*>.*<\/pre>/ismU', |
| | | array('html2text', '_preg_pre_callback'), $text, 1); |
| | | // free memory |
| | | $this->pre_content = ''; |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * @param array PREG matches |
| | | * @return string |
| | | * @access private |
| | | */ |
| | | function _preg_callback($matches) |
| | | private function _preg_callback($matches) |
| | | { |
| | | switch($matches[1]) { |
| | | case 'b': |
| | |
| | | } |
| | | |
| | | /** |
| | | * Callback function for preg_replace_callback use in PRE content handler. |
| | | * |
| | | * @param array PREG matches |
| | | * @return string |
| | | */ |
| | | private function _preg_pre_callback($matches) |
| | | { |
| | | return $this->pre_content; |
| | | } |
| | | |
| | | /** |
| | | * Strtoupper multibyte wrapper function |
| | | * |
| | | * @param string |
| | | * @return string |
| | | * @access private |
| | | */ |
| | | function _strtoupper($str) |
| | | private function _strtoupper($str) |
| | | { |
| | | if (function_exists('mb_strtoupper')) |
| | | return mb_strtoupper($str); |
| | |
| | | $body = preg_replace_callback($replacer->mailto_pattern, array($replacer, 'mailto_callback'), $body); |
| | | |
| | | // split body into single lines |
| | | $a_lines = preg_split('/\r?\n/', $body); |
| | | $body = preg_split('/\r?\n/', $body); |
| | | $quote_level = 0; |
| | | $last = -1; |
| | | |
| | | // find/mark quoted lines... |
| | | for ($n=0, $cnt=count($a_lines); $n < $cnt; $n++) { |
| | | if ($a_lines[$n][0] == '>' && preg_match('/^(>+\s*)+/', $a_lines[$n], $regs)) { |
| | | for ($n=0, $cnt=count($body); $n < $cnt; $n++) { |
| | | if ($body[$n][0] == '>' && preg_match('/^(>+\s*)+/', $body[$n], $regs)) { |
| | | $q = strlen(preg_replace('/\s/', '', $regs[0])); |
| | | $a_lines[$n] = substr($a_lines[$n], strlen($regs[0])); |
| | | $body[$n] = substr($body[$n], strlen($regs[0])); |
| | | |
| | | if ($q > $quote_level) |
| | | $a_lines[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('<blockquote>', $q - $quote_level))) . $a_lines[$n]; |
| | | else if ($q < $quote_level) |
| | | $a_lines[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level - $q))) . $a_lines[$n]; |
| | | if ($q > $quote_level) { |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('<blockquote>', $q - $quote_level))) . $body[$n]; |
| | | } |
| | | else if ($q < $quote_level) { |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level - $q))) . $body[$n]; |
| | | } |
| | | else if ($flowed) { |
| | | // previous line is flowed |
| | | if (isset($a_lines[$last]) && $a_lines[$n] |
| | | && $a_lines[$last][strlen($a_lines[$last])-1] == ' ') { |
| | | if (isset($body[$last]) && $body[$n] |
| | | && $body[$last][strlen($body[$last])-1] == ' ') { |
| | | // merge lines |
| | | $a_lines[$last] .= $a_lines[$n]; |
| | | unset($a_lines[$n]); |
| | | $body[$last] .= $body[$n]; |
| | | unset($body[$n]); |
| | | } |
| | | else |
| | | else { |
| | | $last = $n; |
| | | } |
| | | } |
| | | } |
| | | else { |
| | | $q = 0; |
| | | if ($flowed) { |
| | | // sig separator - line is fixed |
| | | if ($a_lines[$n] == '-- ') { |
| | | $last = $n; |
| | | if ($body[$n] == '-- ') { |
| | | $last = $last_sig = $n; |
| | | } |
| | | else { |
| | | // remove space-stuffing |
| | | if ($a_lines[$n][0] == ' ') |
| | | $a_lines[$n] = substr($a_lines[$n], 1); |
| | | if ($body[$n][0] == ' ') |
| | | $body[$n] = substr($body[$n], 1); |
| | | |
| | | // previous line is flowed? |
| | | if (isset($a_lines[$last]) && $a_lines[$n] |
| | | && $a_lines[$last] != '-- ' |
| | | && $a_lines[$last][strlen($a_lines[$last])-1] == ' ' |
| | | if (isset($body[$last]) && $body[$n] |
| | | && $last != $last_sig |
| | | && $body[$last][strlen($body[$last])-1] == ' ' |
| | | ) { |
| | | $a_lines[$last] .= $a_lines[$n]; |
| | | unset($a_lines[$n]); |
| | | $body[$last] .= $body[$n]; |
| | | unset($body[$n]); |
| | | } |
| | | else { |
| | | $last = $n; |
| | | } |
| | | } |
| | | if ($quote_level > 0) |
| | | $a_lines[$last] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) . $a_lines[$last]; |
| | | $body[$last] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) . $body[$last]; |
| | | } |
| | | else if ($quote_level > 0) |
| | | $a_lines[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) . $a_lines[$n]; |
| | | $body[$n] = $replacer->get_replacement($replacer->add( |
| | | str_repeat('</blockquote>', $quote_level))) . $body[$n]; |
| | | } |
| | | |
| | | $quote_level = $q; |
| | | } |
| | | |
| | | $body = join("\n", $a_lines); |
| | | $body = join("\n", $body); |
| | | |
| | | // quote plain text (don't use Q() here, to display entities "as is") |
| | | $table = get_html_translation_table(HTML_SPECIALCHARS); |
| | |
| | | break; |
| | | } |
| | | |
| | | $data = rcmail::get_instance()->plugins->exec_hook('preferences_save', |
| | | $plugin = rcmail::get_instance()->plugins->exec_hook('preferences_save', |
| | | array('prefs' => $a_user_prefs, 'section' => $CURR_SECTION)); |
| | | |
| | | $a_user_prefs = $data['prefs']; |
| | | $a_user_prefs = $plugin['prefs']; |
| | | |
| | | // don't override these parameters |
| | | foreach ((array)$CONFIG['dont_override'] as $p) |
| | |
| | | break; |
| | | } |
| | | |
| | | if ($USER->save_prefs($a_user_prefs)) |
| | | // Save preferences |
| | | if (!$plugin['abort']) |
| | | $saved = $USER->save_prefs($a_user_prefs); |
| | | else |
| | | $saved = $plugin['result']; |
| | | |
| | | if ($saved) |
| | | $OUTPUT->show_message('successfullysaved', 'confirmation'); |
| | | else |
| | | $OUTPUT->show_message($plugin['message'] ? $plugin['message'] : 'errorsaving', 'error'); |
| | | |
| | | // display the form again |
| | | rcmail_overwrite_action('edit-prefs'); |
| | | |
| | | |