Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F224803
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
41 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index ab0ef481e..d56ea9b17 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -1,597 +1,597 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcube_ldap.php |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2006-2008, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Interface to an LDAP address directory |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
/**
* Model class to access an LDAP address directory
*
* @package Addressbook
*/
class rcube_ldap
{
var $conn;
var $prop = array();
var $fieldmap = array();
var $filter = '';
var $result = null;
var $ldap_result = null;
var $sort_col = '';
/** public properties */
var $primary_key = 'ID';
var $readonly = true;
var $list_page = 1;
var $page_size = 10;
var $ready = false;
/**
* Object constructor
*
* @param array LDAP connection properties
* @param integer User-ID
*/
function __construct($p)
{
$this->prop = $p;
foreach ($p as $prop => $value)
if (preg_match('/^(.+)_field$/', $prop, $matches))
$this->fieldmap[$matches[1]] = $value;
$this->sort_col = $p["sort"];
$this->connect();
}
/**
* Establish a connection to the LDAP server
*/
function connect()
{
global $RCMAIL;
if (!function_exists('ldap_connect'))
- raise_error(array('type' => 'ldap', 'message' => "No ldap support in this installation of PHP"), true);
+ raise_error(array('code' => 100, 'type' => 'ldap', 'message' => "No ldap support in this installation of PHP"), true);
if (is_resource($this->conn))
return true;
if (!is_array($this->prop['hosts']))
$this->prop['hosts'] = array($this->prop['hosts']);
if (empty($this->prop['ldap_version']))
$this->prop['ldap_version'] = 3;
foreach ($this->prop['hosts'] as $host)
{
if ($lc = @ldap_connect($host, $this->prop['port']))
{
if ($this->prop['use_tls']===true)
if (!ldap_start_tls($lc))
continue;
ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']);
$this->prop['host'] = $host;
$this->conn = $lc;
break;
}
}
if (is_resource($this->conn))
{
$this->ready = true;
// User specific access, generate the proper values to use.
if ($this->prop["user_specific"]) {
// No password set, use the session password
if (empty($this->prop['bind_pass'])) {
$this->prop['bind_pass'] = $RCMAIL->decrypt_passwd($_SESSION["password"]);
}
// Get the pieces needed for variable replacement.
$fu = $RCMAIL->user->get_username();
list($u, $d) = explode('@', $fu);
// Replace the bind_dn and base_dn variables.
$replaces = array('%fu' => $fu, '%u' => $u, '%d' => $d);
$this->prop['bind_dn'] = strtr($this->prop['bind_dn'], $replaces);
$this->prop['base_dn'] = strtr($this->prop['base_dn'], $replaces);
}
if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass']))
$this->ready = $this->bind($this->prop['bind_dn'], $this->prop['bind_pass']);
}
else
- raise_error(array('type' => 'ldap', 'message' => "Could not connect to any LDAP server, tried $host:{$this->prop[port]} last"), true);
+ raise_error(array('code' => 100, 'type' => 'ldap', 'message' => "Could not connect to any LDAP server, tried $host:{$this->prop[port]} last"), true);
// See if the directory is writeable.
if ($this->prop['writable']) {
$this->readonly = false;
} // end if
}
/**
* Bind connection with DN and password
*
* @param string Bind DN
* @param string Bind password
* @return boolean True on success, False on error
*/
function bind($dn, $pass)
{
if (!$this->conn) {
return false;
}
if (@ldap_bind($this->conn, $dn, $pass)) {
return true;
}
raise_error(array(
'code' => ldap_errno($this->conn),
'type' => 'ldap',
'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)),
true);
return false;
}
/**
* Close connection to LDAP server
*/
function close()
{
if ($this->conn)
{
@ldap_unbind($this->conn);
$this->conn = null;
}
}
/**
* Set internal list page
*
* @param number Page number to list
* @access public
*/
function set_page($page)
{
$this->list_page = (int)$page;
}
/**
* Set internal page size
*
* @param number Number of messages to display on one page
* @access public
*/
function set_pagesize($size)
{
$this->page_size = (int)$size;
}
/**
* Save a search string for future listings
*
* @param string Filter string
*/
function set_search_set($filter)
{
$this->filter = $filter;
}
/**
* Getter for saved search properties
*
* @return mixed Search properties used by this class
*/
function get_search_set()
{
return $this->filter;
}
/**
* Reset all saved results and search parameters
*/
function reset()
{
$this->result = null;
$this->ldap_result = null;
$this->filter = '';
}
/**
* List the current set of contact records
*
* @param array List of cols to show
* @param int Only return this number of records
* @return array Indexed list of contact records, each a hash array
*/
function list_records($cols=null, $subset=0)
{
// add general filter to query
if (!empty($this->prop['filter']) && empty($this->filter))
{
$filter = $this->prop['filter'];
$this->set_search_set($filter);
}
// exec LDAP search if no result resource is stored
if ($this->conn && !$this->ldap_result)
$this->_exec_search();
// count contacts for this user
$this->result = $this->count();
// we have a search result resource
if ($this->ldap_result && $this->result->count > 0)
{
if ($this->sort_col && $this->prop['scope'] !== "base")
@ldap_sort($this->conn, $this->ldap_result, $this->sort_col);
$start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first;
$last_row = $this->result->first + $this->page_size;
$last_row = $subset != 0 ? $start_row + abs($subset) : $last_row;
$entries = ldap_get_entries($this->conn, $this->ldap_result);
for ($i = $start_row; $i < min($entries['count'], $last_row); $i++)
$this->result->add($this->_ldap2result($entries[$i]));
}
return $this->result;
}
/**
* Search contacts
*
* @param array List of fields to search in
* @param string Search value
* @param boolean True if results are requested, False if count only
* @return array Indexed list of contact records and 'count' value
*/
function search($fields, $value, $strict=false, $select=true)
{
// special treatment for ID-based search
if ($fields == 'ID' || $fields == $this->primary_key)
{
$ids = explode(',', $value);
$result = new rcube_result_set();
foreach ($ids as $id)
if ($rec = $this->get_record($id, true))
{
$result->add($rec);
$result->count++;
}
return $result;
}
$filter = '(|';
$wc = !$strict && $this->prop['fuzzy_search'] ? '*' : '';
if (is_array($this->prop['search_fields']))
{
foreach ($this->prop['search_fields'] as $k => $field)
$filter .= "($field=$wc" . rcube_ldap::quote_string($value) . "$wc)";
}
else
{
foreach ((array)$fields as $field)
if ($f = $this->_map_field($field))
$filter .= "($f=$wc" . rcube_ldap::quote_string($value) . "$wc)";
}
$filter .= ')';
// avoid double-wildcard if $value is empty
$filter = preg_replace('/\*+/', '*', $filter);
// add general filter to query
if (!empty($this->prop['filter']))
$filter = '(&(' . preg_replace('/^\(|\)$/', '', $this->prop['filter']) . ')' . $filter . ')';
// set filter string and execute search
$this->set_search_set($filter);
$this->_exec_search();
if ($select)
$this->list_records();
else
$this->result = $this->count();
return $this->result;
}
/**
* Count number of available contacts in database
*
* @return object rcube_result_set Resultset with values for 'count' and 'first'
*/
function count()
{
$count = 0;
if ($this->conn && $this->ldap_result) {
$count = ldap_count_entries($this->conn, $this->ldap_result);
} // end if
elseif ($this->conn) {
// We have a connection but no result set, attempt to get one.
if (empty($this->filter)) {
// The filter is not set, set it.
$this->filter = $this->prop['filter'];
} // end if
$this->_exec_search();
if ($this->ldap_result) {
$count = ldap_count_entries($this->conn, $this->ldap_result);
} // end if
} // end else
return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
}
/**
* Return the last result set
*
* @return object rcube_result_set Current resultset or NULL if nothing selected yet
*/
function get_result()
{
return $this->result;
}
/**
* Get a specific contact record
*
* @param mixed Record identifier
* @param boolean Return as associative array
* @return mixed Hash array or rcube_result_set with all record fields
*/
function get_record($dn, $assoc=false)
{
$res = null;
if ($this->conn && $dn)
{
$this->ldap_result = @ldap_read($this->conn, base64_decode($dn), "(objectclass=*)", array_values($this->fieldmap));
$entry = @ldap_first_entry($this->conn, $this->ldap_result);
if ($entry && ($rec = ldap_get_attributes($this->conn, $entry)))
{
// Add in the dn for the entry.
$rec["dn"] = base64_decode($dn);
$res = $this->_ldap2result($rec);
$this->result = new rcube_result_set(1);
$this->result->add($res);
}
}
return $assoc ? $res : $this->result;
}
/**
* Create a new contact record
*
* @param array Hash array with save data
* @return encoded record ID on success, False on error
*/
function insert($save_cols)
{
// Map out the column names to their LDAP ones to build the new entry.
$newentry = array();
$newentry["objectClass"] = $this->prop["LDAP_Object_Classes"];
foreach ($save_cols as $col => $val) {
$fld = "";
$fld = $this->_map_field($col);
if ($fld != "") {
// The field does exist, add it to the entry.
$newentry[$fld] = $val;
} // end if
} // end foreach
// Verify that the required fields are set.
// We know that the email address is required as a default of rcube, so
// we will default its value into any unfilled required fields.
foreach ($this->prop["required_fields"] as $fld) {
if (!isset($newentry[$fld])) {
$newentry[$fld] = $newentry[$this->_map_field("email")];
} // end if
} // end foreach
// Build the new entries DN.
$dn = $this->prop["LDAP_rdn"]."=".$newentry[$this->prop["LDAP_rdn"]].",".$this->prop['base_dn'];
$res = @ldap_add($this->conn, $dn, $newentry);
if ($res === FALSE) {
return false;
} // end if
return base64_encode($dn);
}
/**
* Update a specific contact record
*
* @param mixed Record identifier
* @param array Hash array with save data
* @return boolean True on success, False on error
*/
function update($id, $save_cols)
{
$record = $this->get_record($id, true);
$result = $this->get_result();
$record = $result->first();
$newdata = array();
$replacedata = array();
$deletedata = array();
foreach ($save_cols as $col => $val) {
$fld = "";
$fld = $this->_map_field($col);
if ($fld != "") {
// The field does exist compare it to the ldap record.
if ($record[$col] != $val) {
// Changed, but find out how.
if (!isset($record[$col])) {
// Field was not set prior, need to add it.
$newdata[$fld] = $val;
} // end if
elseif ($val == "") {
// Field supplied is empty, verify that it is not required.
if (!in_array($fld, $this->prop["required_fields"])) {
// It is not, safe to clear.
$deletedata[$fld] = $record[$col];
} // end if
} // end elseif
else {
// The data was modified, save it out.
$replacedata[$fld] = $val;
} // end else
} // end if
} // end if
} // end foreach
// Update the entry as required.
$dn = base64_decode($id);
if (!empty($deletedata)) {
// Delete the fields.
$res = @ldap_mod_del($this->conn, $dn, $deletedata);
if ($res === FALSE) {
return false;
} // end if
} // end if
if (!empty($replacedata)) {
// Replace the fields.
$res = @ldap_mod_replace($this->conn, $dn, $replacedata);
if ($res === FALSE) {
return false;
} // end if
} // end if
if (!empty($newdata)) {
// Add the fields.
$res = @ldap_mod_add($this->conn, $dn, $newdata);
if ($res === FALSE) {
return false;
} // end if
} // end if
return true;
}
/**
* Mark one or more contact records as deleted
*
* @param array Record identifiers
* @return boolean True on success, False on error
*/
function delete($ids)
{
if (!is_array($ids)) {
// Not an array, break apart the encoded DNs.
$dns = explode(",", $ids);
} // end if
foreach ($dns as $id) {
$dn = base64_decode($id);
// Delete the record.
$res = @ldap_delete($this->conn, $dn);
if ($res === FALSE) {
return false;
} // end if
} // end foreach
return true;
}
/**
* Execute the LDAP search based on the stored credentials
*
* @access private
*/
function _exec_search()
{
if ($this->ready && $this->filter)
{
$function = $this->prop['scope'] == 'sub' ? 'ldap_search' : ($this->prop['scope'] == 'base' ? 'ldap_read' : 'ldap_list');
$this->ldap_result = $function($this->conn, $this->prop['base_dn'], $this->filter, array_values($this->fieldmap), 0, 0);
return true;
}
else
return false;
}
/**
* @access private
*/
function _ldap2result($rec)
{
$out = array();
if ($rec['dn'])
$out[$this->primary_key] = base64_encode($rec['dn']);
foreach ($this->fieldmap as $rf => $lf)
{
if ($rec[$lf]['count'])
$out[$rf] = $rec[$lf][0];
}
return $out;
}
/**
* @access private
*/
function _map_field($field)
{
return $this->fieldmap[$field];
}
/**
* @static
*/
function quote_string($str)
{
return strtr($str, array('*'=>'\2a', '('=>'\28', ')'=>'\29', '\\'=>'\5c'));
}
}
diff --git a/program/lib/utf8.class.php b/program/lib/utf8.class.php
index e2d10599d..2bbe63663 100644
--- a/program/lib/utf8.class.php
+++ b/program/lib/utf8.class.php
@@ -1,176 +1,177 @@
<?php
/*
utf8 1.0
Copyright: Left
---------------------------------------------------------------------------------
Version: 1.0
Date: 23 November 2004
---------------------------------------------------------------------------------
Author: Alexander Minkovsky (a_minkovsky@hotmail.com)
---------------------------------------------------------------------------------
License: Choose the more appropriated for You - I don't care.
---------------------------------------------------------------------------------
Description:
Class provides functionality to convert single byte strings, such as CP1251
ti UTF-8 multibyte format and vice versa.
Class loads a concrete charset map, for example CP1251.
(Refer to ftp://ftp.unicode.org/Public/MAPPINGS/ for map files)
Directory containing MAP files is predefined as constant.
Each charset is also predefined as constant pointing to the MAP file.
---------------------------------------------------------------------------------
Example usage:
Pass the desired charset in the class constructor:
$utfConverter = new utf8(CP1251); //defaults to CP1250.
or load the charset MAP using loadCharset method like this:
$utfConverter->loadCharset(CP1252);
Then call
$res = $utfConverter->strToUtf8($str);
or
$res = $utfConverter->utf8ToStr($utf);
to get the needed encoding.
---------------------------------------------------------------------------------
Note:
Rewrite or Override the onError method if needed. It's the error handler used from everywhere and takes 2 parameters:
err_code and err_text. By default it just prints out a message about the error.
*/
// Charset maps
// Adapted to fit RoundCube
define("UTF8_MAP_DIR", "program/lib/encoding");
$utf8_maps = array(
"CP1250" => UTF8_MAP_DIR . "/CP1250.map",
"CP1251" => UTF8_MAP_DIR . "/CP1251.map",
"CP1252" => UTF8_MAP_DIR . "/CP1252.map",
"CP1253" => UTF8_MAP_DIR . "/CP1253.map",
"CP1254" => UTF8_MAP_DIR . "/CP1254.map",
"CP1255" => UTF8_MAP_DIR . "/CP1255.map",
"CP1256" => UTF8_MAP_DIR . "/CP1256.map",
"CP1257" => UTF8_MAP_DIR . "/CP1257.map",
"CP1258" => UTF8_MAP_DIR . "/CP1258.map",
"ISO-8859-1" => UTF8_MAP_DIR . "/ISO-8859-1.map",
"ISO-8859-2" => UTF8_MAP_DIR . "/ISO-8859-2.map",
"ISO-8859-3" => UTF8_MAP_DIR . "/ISO-8859-3.map",
"ISO-8859-4" => UTF8_MAP_DIR . "/ISO-8859-4.map",
"ISO-8859-5" => UTF8_MAP_DIR . "/ISO-8859-5.map",
"ISO-8859-6" => UTF8_MAP_DIR . "/ISO-8859-6.map",
"ISO-8859-7" => UTF8_MAP_DIR . "/ISO-8859-7.map",
"ISO-8859-8" => UTF8_MAP_DIR . "/ISO-8859-8.map",
"ISO-8859-9" => UTF8_MAP_DIR . "/ISO-8859-9.map",
"KOI8-R" => UTF8_MAP_DIR . "/KOI8R.map",
"KOI8R" => UTF8_MAP_DIR . "/KOI8R.map"
);
//Error constants
define("ERR_OPEN_MAP_FILE","ERR_OPEN_MAP_FILE");
//Class definition
Class utf8{
var $charset = "ISO-8859-1";
var $ascMap = array();
var $utfMap = array();
function __construct($charset="ISO-8859-1"){
$this->loadCharset($charset);
}
//Load charset
function loadCharset($charset){
global $utf8_maps;
if (!is_file($utf8_maps[$charset]))
{
$this->onError(ERR_OPEN_MAP_FILE, "Failed to open map file for $charset");
return;
}
if (empty($this->ascMap[$charset]))
{
$lines = file_get_contents($utf8_maps[$charset]);
$lines = preg_replace("/#.*$/m","",$lines);
$lines = preg_replace("/\n\n/","",$lines);
$lines = explode("\n",$lines);
foreach($lines as $line){
$parts = explode('0x',$line);
if(count($parts)==3){
$asc=hexdec(substr($parts[1],0,2));
$utf=hexdec(substr($parts[2],0,4));
$this->ascMap[$charset][$asc]=$utf;
}
}
}
$this->charset = $charset;
$this->utfMap = array_flip($this->ascMap[$charset]);
}
//Error handler
function onError($err_code,$err_text){
//print($err_code . " : " . $err_text . "<hr>\n");
raise_error(array('code' => 500,
+ 'type' => 'php',
'file' => __FILE__,
'message' => $err_text), TRUE, FALSE);
}
//Translate string ($str) to UTF-8 from given charset
function strToUtf8($str){
$chars = unpack('C*', $str);
$cnt = count($chars);
for($i=1;$i<=$cnt;$i++) $this->_charToUtf8($chars[$i]);
return implode("",$chars);
}
//Translate UTF-8 string to single byte string in the given charset
function utf8ToStr($utf){
$chars = unpack('C*', $utf);
$cnt = count($chars);
$res = ""; //No simple way to do it in place... concatenate char by char
for ($i=1;$i<=$cnt;$i++){
$res .= $this->_utf8ToChar($chars, $i);
}
return $res;
}
//Char to UTF-8 sequence
function _charToUtf8(&$char){
$c = (int)$this->ascMap[$this->charset][$char];
if ($c < 0x80){
$char = chr($c);
}
else if($c<0x800) // 2 bytes
$char = (chr(0xC0 | $c>>6) . chr(0x80 | $c & 0x3F));
else if($c<0x10000) // 3 bytes
$char = (chr(0xE0 | $c>>12) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F));
else if($c<0x200000) // 4 bytes
$char = (chr(0xF0 | $c>>18) . chr(0x80 | $c>>12 & 0x3F) . chr(0x80 | $c>>6 & 0x3F) . chr(0x80 | $c & 0x3F));
}
//UTF-8 sequence to single byte character
function _utf8ToChar(&$chars, &$idx){
if(($chars[$idx] >= 240) && ($chars[$idx] <= 255)){ // 4 bytes
$utf = (intval($chars[$idx]-240) << 18) +
(intval($chars[++$idx]-128) << 12) +
(intval($chars[++$idx]-128) << 6) +
(intval($chars[++$idx]-128) << 0);
}
else if (($chars[$idx] >= 224) && ($chars[$idx] <= 239)){ // 3 bytes
$utf = (intval($chars[$idx]-224) << 12) +
(intval($chars[++$idx]-128) << 6) +
(intval($chars[++$idx]-128) << 0);
}
else if (($chars[$idx] >= 192) && ($chars[$idx] <= 223)){ // 2 bytes
$utf = (intval($chars[$idx]-192) << 6) +
(intval($chars[++$idx]-128) << 0);
}
else{ // 1 byte
$utf = $chars[$idx];
}
if(array_key_exists($utf,$this->utfMap))
return chr($this->utfMap[$utf]);
else
return "?";
}
}
-?>
\ No newline at end of file
+?>
diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc
index 8e8d13919..b065c2a25 100644
--- a/program/steps/mail/sendmail.inc
+++ b/program/steps/mail/sendmail.inc
@@ -1,476 +1,476 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/sendmail.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2008, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Compose a new mail message with all headers and attachments |
| and send it using the PEAR::Net_SMTP class or with PHP mail() |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
// remove all scripts and act as called in frame
$OUTPUT->reset();
$OUTPUT->framed = TRUE;
$savedraft = !empty($_POST['_draft']) ? TRUE : FALSE;
/****** checks ********/
if (!isset($_SESSION['compose']['id'])) {
- raise_error(array('code' => 500, 'file' => __FILE__, 'message' => "Invalid compose ID"), true, false);
+ raise_error(array('code' => 500, 'type' => 'smtp', 'file' => __FILE__, 'message' => "Invalid compose ID"), true, false);
console("Sendmail error", $_SESSION['compose']);
$OUTPUT->show_message("An internal error occured. Please try again.", 'error');
$OUTPUT->send('iframe');
}
if (!$savedraft) {
if (empty($_POST['_to']) && empty($_POST['_cc']) && empty($_POST['_bcc'])
&& empty($_POST['_subject']) && $_POST['_message']) {
$OUTPUT->show_message('sendingfailed', 'error');
$OUTPUT->send('iframe');
}
if(!empty($CONFIG['sendmail_delay'])) {
$wait_sec = time() - intval($CONFIG['sendmail_delay']) - intval($CONFIG['last_message_time']);
if($wait_sec < 0) {
$OUTPUT->show_message('senttooquickly', 'error', array('sec' => $wait_sec * -1));
$OUTPUT->send('iframe');
}
}
}
/****** message sending functions ********/
// get identity record
function rcmail_get_identity($id)
{
global $USER, $OUTPUT;
if ($sql_arr = $USER->get_identity($id))
{
$out = $sql_arr;
$out['mailto'] = $sql_arr['email'];
// Special chars as defined by RFC 822 need to in quoted string (or escaped).
if (preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $sql_arr['name']))
$name = '"' . addcslashes($sql_arr['name'], '"') . '"';
else
$name = $sql_arr['name'];
$out['string'] = rcube_charset_convert($name, RCMAIL_CHARSET, $OUTPUT->get_charset());
if ($sql_arr['email'])
$out['string'] .= ' <' . $sql_arr['email'] . '>';
return $out;
}
return FALSE;
}
/**
* go from this:
* <img src=".../tiny_mce/plugins/emotions/images/smiley-cool.gif" border="0" alt="Cool" title="Cool" />
*
* to this:
*
* <IMG src="cid:smiley-cool.gif"/>
* ...
* ------part...
* Content-Type: image/gif
* Content-Transfer-Encoding: base64
* Content-ID: <smiley-cool.gif>
*/
function rcmail_attach_emoticons(&$mime_message)
{
global $CONFIG;
$htmlContents = $mime_message->getHtmlBody();
// remove any null-byte characters before parsing
$body = preg_replace('/\x00/', '', $htmlContents);
$last_img_pos = 0;
$searchstr = 'program/js/tiny_mce/plugins/emotions/img/';
$path_len = strlen(INSTALL_PATH . '/');
// keep track of added images, so they're only added once
$included_images = array();
// find emoticon image tags
while ($pos = strpos($body, $searchstr, $last_img_pos))
{
$pos2 = strpos($body, '"', $pos);
$body_pre = substr($body, 0, $pos);
$body_post = substr($body, $pos2);
$image_name = substr($body,
$pos + strlen($searchstr),
$pos2 - ($pos + strlen($searchstr)));
// sanitize image name so resulting attachment doesn't leave images dir
$image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i','',$image_name);
$img_file = INSTALL_PATH . '/' . $searchstr . $image_name;
if (! in_array($image_name, $included_images))
{
// add the image to the MIME message
if(! $mime_message->addHTMLImage($img_file, 'image/gif', '', true, $image_name))
$OUTPUT->show_message("emoticonerror", 'error');
array_push($included_images, $image_name);
}
$body = $body_pre . $img_file . $body_post;
$last_img_pos = $pos2 + $path_len;
}
$mime_message->setHTMLBody($body);
}
/****** compose message ********/
if (strlen($_POST['_draft_saveid']) > 3)
$olddraftmessageid = get_input_value('_draft_saveid', RCUBE_INPUT_POST);
$message_id = sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), $RCMAIL->config->mail_domain($_SESSION['imap_host']));
// set default charset
$input_charset = $OUTPUT->get_charset();
$message_charset = isset($_POST['_charset']) ? $_POST['_charset'] : $input_charset;
$mailto_regexp = array('/[,;]\s*[\r\n]+/', '/[\r\n]+/', '/[,;]\s*$/m', '/;/', '/(\S{1})(<\S+@\S+>)/U');
$mailto_replace = array(', ', ', ', '', ',', '\\1 \\2');
// replace new lines and strip ending ', ', make address strings more valid also
$mailto = preg_replace($mailto_regexp, $mailto_replace, get_input_value('_to', RCUBE_INPUT_POST, TRUE, $message_charset));
$mailcc = preg_replace($mailto_regexp, $mailto_replace, get_input_value('_cc', RCUBE_INPUT_POST, TRUE, $message_charset));
$mailbcc = preg_replace($mailto_regexp, $mailto_replace, get_input_value('_bcc', RCUBE_INPUT_POST, TRUE, $message_charset));
if (empty($mailto) && !empty($mailcc)) {
$mailto = $mailcc;
$mailcc = null;
}
else if (empty($mailto))
$mailto = 'undisclosed-recipients:;';
// get sender name and address
$from = get_input_value('_from', RCUBE_INPUT_POST);
$identity_arr = rcmail_get_identity($from);
if ($identity_arr)
$from = $identity_arr['mailto'];
if (empty($identity_arr['string']))
$identity_arr['string'] = $from;
// compose headers array
$headers = array('Date' => date('r'),
'From' => rcube_charset_convert($identity_arr['string'], RCMAIL_CHARSET, $message_charset),
'To' => $mailto);
// additional recipients
if (!empty($mailcc))
$headers['Cc'] = $mailcc;
if (!empty($mailbcc))
$headers['Bcc'] = $mailbcc;
if (!empty($identity_arr['bcc']))
$headers['Bcc'] = ($headers['Bcc'] ? $headers['Bcc'].', ' : '') . $identity_arr['bcc'];
// add subject
$headers['Subject'] = trim(get_input_value('_subject', RCUBE_INPUT_POST, FALSE, $message_charset));
if (!empty($identity_arr['organization']))
$headers['Organization'] = $identity_arr['organization'];
if (!empty($_POST['_replyto']))
$headers['Reply-To'] = preg_replace($mailto_regexp, $mailto_replace, get_input_value('_replyto', RCUBE_INPUT_POST, TRUE, $message_charset));
else if (!empty($identity_arr['reply-to']))
$headers['Reply-To'] = $identity_arr['reply-to'];
if (!empty($_SESSION['compose']['reply_msgid']))
$headers['In-Reply-To'] = $_SESSION['compose']['reply_msgid'];
if (!empty($_SESSION['compose']['references']))
$headers['References'] = $_SESSION['compose']['references'];
if (!empty($_POST['_priority']))
{
$priority = intval($_POST['_priority']);
$a_priorities = array(1=>'highest', 2=>'high', 4=>'low', 5=>'lowest');
if ($str_priority = $a_priorities[$priority])
$headers['X-Priority'] = sprintf("%d (%s)", $priority, ucfirst($str_priority));
}
if (!empty($_POST['_receipt']))
{
$headers['Return-Receipt-To'] = $identity_arr['string'];
$headers['Disposition-Notification-To'] = $identity_arr['string'];
}
// additional headers
if ($CONFIG['http_received_header'])
{
$nldlm = $RCMAIL->config->header_delimiter() . "\t";
$headers['Received'] = wordwrap('from ' . (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ?
gethostbyaddr($_SERVER['HTTP_X_FORWARDED_FOR']).' ['.$_SERVER['HTTP_X_FORWARDED_FOR'].']'.$nldlm.' via ' : '') .
gethostbyaddr($_SERVER['REMOTE_ADDR']).' ['.$_SERVER['REMOTE_ADDR'].']'.$nldlm.'with ' .
$_SERVER['SERVER_PROTOCOL'].' ('.$_SERVER['REQUEST_METHOD'].'); ' . date('r'),
69, $nldlm);
}
$headers['Message-ID'] = $message_id;
$headers['X-Sender'] = $from;
if (!empty($CONFIG['useragent']))
$headers['User-Agent'] = $CONFIG['useragent'];
$isHtmlVal = strtolower(get_input_value('_is_html', RCUBE_INPUT_POST));
$isHtml = ($isHtmlVal == "1");
// fetch message body
$message_body = get_input_value('_message', RCUBE_INPUT_POST, TRUE, $message_charset);
// remove signature's div ID
if (!$savedraft && $isHtml)
$message_body = preg_replace('/\s*id="_rc_sig"/', '', $message_body);
// append generic footer to all messages
if (!$savedraft && !empty($CONFIG['generic_message_footer']) && ($footer = file_get_contents(realpath($CONFIG['generic_message_footer']))))
$message_body .= "\r\n" . rcube_charset_convert($footer, 'UTF-8', $message_charset);
// create extended PEAR::Mail_mime instance
$MAIL_MIME = new rcube_mail_mime($RCMAIL->config->header_delimiter());
// For HTML-formatted messages, construct the MIME message with both
// the HTML part and the plain-text part
if ($isHtml)
{
$MAIL_MIME->setHTMLBody($message_body);
// add a plain text version of the e-mail as an alternative part.
$h2t = new html2text($message_body);
$plainTextPart = wordwrap($h2t->get_text(), 998, "\r\n", true);
if (!strlen($plainTextPart))
{
// empty message body breaks attachment handling in drafts
$plainTextPart = "\r\n";
}
$MAIL_MIME->setTXTBody($plainTextPart);
// look for "emoticon" images from TinyMCE and copy into message as attachments
rcmail_attach_emoticons($MAIL_MIME);
}
else
{
$message_body = wordwrap($message_body, 75, "\r\n");
$message_body = wordwrap($message_body, 998, "\r\n", true);
if (!strlen($message_body))
{
// empty message body breaks attachment handling in drafts
$message_body = "\r\n";
}
$MAIL_MIME->setTXTBody($message_body, FALSE, TRUE);
}
// chose transfer encoding
$charset_7bit = array('ASCII', 'ISO-2022-JP', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-15');
$transfer_encoding = in_array(strtoupper($message_charset), $charset_7bit) ? '7bit' : '8bit';
// add stored attachments, if any
if (is_array($_SESSION['compose']['attachments']))
foreach ($_SESSION['compose']['attachments'] as $id => $attachment)
{
$dispurl = '/\ssrc\s*=\s*[\'"]?\S+display-attachment\S+file=rcmfile' . $id . '[\'"]?/';
$match = preg_match($dispurl, $message_body);
if ($isHtml && ($match > 0))
{
$message_body = preg_replace($dispurl, ' src="'.$attachment['name'].'"', $message_body);
$MAIL_MIME->setHTMLBody($message_body);
$MAIL_MIME->addHTMLImage($attachment['path'], $attachment['mimetype'], $attachment['name']);
}
else
{
$ctype = str_replace('image/pjpeg', 'image/jpeg', $attachment['mimetype']); // #1484914
// .eml attachments send inline
$MAIL_MIME->addAttachment($attachment['path'],
$ctype,
$attachment['name'], true,
($ctype == 'message/rfc822' ? $transfer_encoding : 'base64'),
($ctype == 'message/rfc822' ? 'inline' : 'attachment'),
$message_charset, '', '',
$CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
$CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
);
}
}
// add submitted attachments
if (is_array($_FILES['_attachments']['tmp_name']))
foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath)
{
$ctype = $files['type'][$i];
$ctype = str_replace('image/pjpeg', 'image/jpeg', $ctype); // #1484914
$MAIL_MIME->addAttachment($filepath, $ctype, $files['name'][$i], true,
$ctype == 'message/rfc822' ? $transfer_encoding : 'base64',
'attachment', $message_charset, '', '',
$CONFIG['mime_param_folding'] ? 'quoted-printable' : NULL,
$CONFIG['mime_param_folding'] == 2 ? 'quoted-printable' : NULL
);
}
// encoding settings for mail composing
$MAIL_MIME->setParam(array(
'text_encoding' => $transfer_encoding,
'html_encoding' => 'quoted-printable',
'head_encoding' => 'quoted-printable',
'head_charset' => $message_charset,
'html_charset' => $message_charset,
'text_charset' => $message_charset,
));
// encoding subject header with mb_encode provides better results with asian characters
if (function_exists("mb_encode_mimeheader"))
{
mb_internal_encoding($message_charset);
$headers['Subject'] = mb_encode_mimeheader($headers['Subject'], $message_charset, 'Q');
mb_internal_encoding(RCMAIL_CHARSET);
}
// pass headers to message object
$MAIL_MIME->headers($headers);
// Begin SMTP Delivery Block
if (!$savedraft)
{
// check for 'From' address (identity may be incomplete)
if ($identity_arr && !$identity_arr['mailto']) {
$OUTPUT->show_message('nofromaddress', 'error');
$OUTPUT->send('iframe');
}
$sent = rcmail_deliver_message($MAIL_MIME, $from, $mailto);
// return to compose page if sending failed
if (!$sent)
{
$OUTPUT->show_message("sendingfailed", 'error');
$OUTPUT->send('iframe');
}
// save message sent time
if (!empty($CONFIG['sendmail_delay']))
$RCMAIL->user->save_prefs(array('last_message_time' => time()));
// set replied/forwarded flag
if ($_SESSION['compose']['reply_uid'])
$IMAP->set_flag($_SESSION['compose']['reply_uid'], 'ANSWERED');
else if ($_SESSION['compose']['forward_uid'])
$IMAP->set_flag($_SESSION['compose']['forward_uid'], 'FORWARDED');
} // End of SMTP Delivery Block
// Determine which folder to save message
if ($savedraft)
$store_target = $CONFIG['drafts_mbox'];
else
$store_target = isset($_POST['_store_target']) ? get_input_value('_store_target', RCUBE_INPUT_POST) : $CONFIG['sent_mbox'];
if ($store_target)
{
// check if mailbox exists
if (!in_array_nocase($store_target, $IMAP->list_mailboxes()))
{
// folder may be existing but not subscribed (#1485241)
if (!in_array_nocase($store_target, $IMAP->list_unsubscribed()))
$store_folder = $IMAP->create_mailbox($store_target, TRUE);
else if ($IMAP->subscribe($store_target))
$store_folder = TRUE;
}
else
$store_folder = TRUE;
// append message to sent box
if ($store_folder)
$saved = $IMAP->save_message($store_target, $MAIL_MIME->getMessage());
// raise error if saving failed
if (!$saved)
{
raise_error(array('code' => 800, 'type' => 'imap', 'file' => __FILE__,
'message' => "Could not save message in $store_target"), TRUE, FALSE);
if ($savedraft) {
$OUTPUT->show_message('errorsaving', 'error');
$OUTPUT->send('iframe');
}
}
if ($olddraftmessageid)
{
// delete previous saved draft
$a_deleteid = $IMAP->search($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$olddraftmessageid);
$deleted = $IMAP->delete_message($IMAP->get_uid($a_deleteid[0], $CONFIG['drafts_mbox']), $CONFIG['drafts_mbox']);
// raise error if deletion of old draft failed
if (!$deleted)
raise_error(array('code' => 800, 'type' => 'imap', 'file' => __FILE__,
'message' => "Could not delete message from ".$CONFIG['drafts_mbox']), TRUE, FALSE);
}
}
if ($savedraft)
{
$msgid = strtr($message_id, array('>' => '', '<' => ''));
// remember new draft-uid
$draftids = $IMAP->search($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid);
$_SESSION['compose']['param']['_draft_uid'] = $IMAP->get_uid($draftids[0], $CONFIG['drafts_mbox']);
// display success
$OUTPUT->show_message('messagesaved', 'confirmation');
// update "_draft_saveid" and the "cmp_hash" to prevent "Unsaved changes" warning
$OUTPUT->command('set_draft_id', $msgid);
$OUTPUT->command('compose_field_hash', true);
// start the auto-save timer again
$OUTPUT->command('auto_save_start');
$OUTPUT->send('iframe');
}
else
{
rcmail_compose_cleanup();
if ($store_folder && !$saved)
$OUTPUT->command('sent_successfully', 'error', rcube_label('errorsavingsent'));
else
$OUTPUT->command('sent_successfully', 'confirmation', rcube_label('messagesent'));
$OUTPUT->send('iframe');
}
?>
diff --git a/program/steps/mail/spell_pspell.inc b/program/steps/mail/spell_pspell.inc
index bf696f2fe..4a829ac48 100644
--- a/program/steps/mail/spell_pspell.inc
+++ b/program/steps/mail/spell_pspell.inc
@@ -1,69 +1,70 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/spell_pspell.inc |
| |
| This file is part of the RoundCube Webmail client |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Use the Pspell extension to check spelling, returns results |
| compatible with spell_googie.inc. |
| |
+-----------------------------------------------------------------------+
| Author: Kris Steinhoff <steinhof@umich.edu> |
+-----------------------------------------------------------------------+
$Id$
*/
if (!extension_loaded('pspell')) {
raise_error(array(
'code' => 500,
+ 'type' => 'php',
'file' => __FILE__,
'message' => "Pspell extension not available"), true, false);
header('HTTP/1.1 404 Not Found');
exit;
}
// read input
$data = file_get_contents('php://input');
// parse data (simplexml_load_string breaks CRLFs)
$left = strpos($data, '<text>');
$right = strrpos($data, '</text>');
$text = substr($data, $left+6, $right-($left+6));
// tokenize
$words = preg_split('/[ !"#$%&()*+\\,-.\/\n:;<=>?@\[\]^_{|}]+/', $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE );
// init spellchecker
$plink = pspell_new(get_input_value('lang', RCUBE_INPUT_GET), null, null, 'utf-8', PSPELL_FAST);
// send output
$out = '<?xml version="1.0" encoding="UTF-8"?><spellresult charschecked="'.rc_strlen($text).'">';
$diff = 0;
foreach ($words as $w) {
$word = trim($w[0]);
$pos = $w[1] - $diff;
$len = rc_strlen($word);
if ($word && $plink && !pspell_check($plink, $word)) {
$suggestions = pspell_suggest($plink, $word);
$out .= '<c o="'.$pos.'" l="'.$len.'">';
$out .= implode("\t", $suggestions);
$out .= '</c>';
}
$diff += (strlen($word) - $len);
}
$out .= '</spellresult>';
header("Content-Type: text/xml");
echo $out;
exit;
?>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Mar 1, 12:37 PM (3 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
166988
Default Alt Text
(41 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment