* Mail/Addressbook/Calendar: add and use charset when sending/receiving mails with vCard/iCals, change default vCard charset preference to utf-8

This commit is contained in:
Ralf Becker 2016-04-29 07:51:13 +00:00
parent b74b3d84f4
commit 0eb3619cd1
10 changed files with 63 additions and 29 deletions

View File

@ -305,7 +305,7 @@ class addressbook_hooks
'help' => 'Which charset should be used for the vCard import and export.', 'help' => 'Which charset should be used for the vCard import and export.',
'xmlrpc' => True, 'xmlrpc' => True,
'admin' => false, 'admin' => false,
'default'=> 'iso-8859-1', 'default'=> 'utf-8',
); );
} }
return $settings; return $settings;

View File

@ -12,9 +12,10 @@
* @version $Id$ * @version $Id$
*/ */
use EGroupware\Api;
/** /**
* Addressbook - vCard parser * Addressbook - vCard parser
*
*/ */
class addressbook_vcal extends addressbook_bo class addressbook_vcal extends addressbook_bo
{ {
@ -555,11 +556,17 @@ class addressbook_vcal extends addressbook_bo
$container = false; $container = false;
$vCard = Horde_Icalendar::newComponent('vcard', $container); $vCard = Horde_Icalendar::newComponent('vcard', $container);
if (!$vCard->parsevCalendar($_vcard, 'VCARD', $charset)) if ($charset && $charset != 'utf-8')
{
$_vcard = Api\Translation::convert($_vcard, $charset, 'utf-8');
}
if (!$vCard->parsevCalendar($_vcard, 'VCARD'))
{ {
return False; return False;
} }
} else { }
else
{
$vCard = $_vcard; $vCard = $_vcard;
} }
$vcardValues = $vCard->getAllAttributes(); $vcardValues = $vCard->getAllAttributes();

View File

@ -230,7 +230,7 @@ app.classes.addressbook = AppJS.extend(
extras.owner.push('c'+ids); extras.owner.push('c'+ids);
} }
} }
if(orgs.length > 0) if(orgs.length > 0)
{ {
// Get organisation contacts, then show infolog list // Get organisation contacts, then show infolog list
@ -704,13 +704,13 @@ app.classes.addressbook = AppJS.extend(
adb_mail_vcard: function(_action, _elems) adb_mail_vcard: function(_action, _elems)
{ {
var app_registry = egw.link_get_registry('mail'); var app_registry = egw.link_get_registry('mail');
if (typeof app_registry['view'] == 'undefined') app_registry = egw.link_get_registry('felamimail');
var link = egw().link("/index.php","menuaction="+app_registry['add']['menuaction']); var link = egw().link("/index.php","menuaction="+app_registry['add']['menuaction']);
for (var i = 0; i < _elems.length; i++) for (var i = 0; i < _elems.length; i++)
{ {
var idToUse = _elems[i].id; var idToUse = _elems[i].id;
var idToUseArray = idToUse.split('::'); var idToUseArray = idToUse.split('::');
idToUse = idToUseArray[1]; idToUse = idToUseArray[1];
link += "&preset[type][]="+encodeURIComponent("text/vcard; charset="+(egw.preference('vcard_charset', 'addressbook') || 'utf-8'));
link += "&preset[file][]="+encodeURIComponent("vfs://default/apps/addressbook/"+idToUse+"/.entry"); link += "&preset[file][]="+encodeURIComponent("vfs://default/apps/addressbook/"+idToUse+"/.entry");
} }
if (typeof app_registry['view'] != 'undefined' && typeof app_registry['view_popup'] != 'undefined' ) if (typeof app_registry['view'] != 'undefined' && typeof app_registry['view_popup'] != 'undefined' )
@ -903,7 +903,7 @@ app.classes.addressbook = AppJS.extend(
break; break;
} }
}, },
/** /**
* Get title in order to set it as document title * Get title in order to set it as document title
* @returns {string} * @returns {string}

View File

@ -253,8 +253,12 @@ class IcalIterator extends Horde_Icalendar implements \Iterator
return; return;
//return PEAR::raiseError("Unable to create object for type $type"); //return PEAR::raiseError("Unable to create object for type $type");
} }
//error_log(__METHOD__."() about to call parsevCalendar('".substr($data,0,100)."...','$type','$this->charset')"); if ($this->charset && $this->charset != 'utf-8')
$this->component->parsevCalendar($data, $type, $this->charset); {
$data = Api\Translation::convert($data, $this->charset, 'utf-8');
}
//error_log(__METHOD__."() about to call parsevCalendar('".substr($data,0,100)."...','$type')");
$this->component->parsevCalendar($data, $type);
// VTIMEZONE components are NOT returned, they are only processed internally // VTIMEZONE components are NOT returned, they are only processed internally
if ($type == 'VTIMEZONE') if ($type == 'VTIMEZONE')

View File

@ -5708,11 +5708,10 @@ class Mail
if ($part && ($partDisposition=='attachment' || $partDisposition=='inline' || ($part->getPrimaryType() == 'text' && $part->getSubType() == 'calendar'))) if ($part && ($partDisposition=='attachment' || $partDisposition=='inline' || ($part->getPrimaryType() == 'text' && $part->getSubType() == 'calendar')))
{ {
//$headerObject=$part->getAllDispositionParameters();//not used anywhere around here //$headerObject=$part->getAllDispositionParameters();//not used anywhere around here
$structure_bytes = $part->getBytes(); $structure_mime = $part->getType();
$structure_mime=$part->getType(); $filename = $part->getName();
$structure_partID=$part->getMimeId(); $charset = $part->getContentTypeParameter('charset');
$filename=$part->getName(); //$structure_bytes = $part->getBytes(); $structure_partID=$part->getMimeId(); error_log(__METHOD__.__LINE__." fetchPartContents(".array2string($_uid).", $structure_partID, $_stream, $_preserveSeen,$structure_mime)" );
//error_log(__METHOD__.__LINE__." fetchPartContents(".array2string($_uid).", $structure_partID, $_stream, $_preserveSeen,$structure_mime)" );
$this->fetchPartContents($_uid, $part, $_stream, $_preserveSeen=true,$structure_mime); $this->fetchPartContents($_uid, $part, $_stream, $_preserveSeen=true,$structure_mime);
if ($_returnPart) return $part; if ($_returnPart) return $part;
} }
@ -5727,8 +5726,8 @@ class Mail
} }
$attachmentData = array( $attachmentData = array(
'type' => $structure_mime, 'type' => $structure_mime,
'charset' => $charset,
'filename' => $filename, 'filename' => $filename,
//'attachment' => $part->getContents(array('stream'=>$_stream))
'attachment' => $part->getContents(array( 'attachment' => $part->getContents(array(
// tnef_decode needs strings not a stream // tnef_decode needs strings not a stream
'stream' => $_stream && !($filename == 'winmail.dat' && $_winmail_nr) 'stream' => $_stream && !($filename == 'winmail.dat' && $_winmail_nr)

View File

@ -321,19 +321,18 @@ class Mailer extends Horde_Mime_Mail
* "text/calendar; method=..." get automatic detected and added as highest priority alternative * "text/calendar; method=..." get automatic detected and added as highest priority alternative
* *
* @param string|resource $data Path to the attachment or open file-descriptor * @param string|resource $data Path to the attachment or open file-descriptor
* @param string $name The file name to use for the attachment. * @param string $name =null file name to use for the attachment
* @param string $type The content type of the file. * @param string $type =null content type of the file, incl. parameters eg. "text/plain; charset=utf-8"
* @param string $charset The character set of the part, only relevant for text parts. * @param string $old_type =null used to support phpMailer signature (deprecated)
* @return integer part-number * @return integer part-number
* @throws Exception\NotFound if $file could not be opened for reading * @throws Exception\NotFound if $file could not be opened for reading
*/ */
public function addAttachment($data, $name = null, $type = null, $charset = 'us-ascii') public function addAttachment($data, $name = null, $type = null, $old_type=null)
{ {
// deprecated PHPMailer::AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') call // deprecated PHPMailer::AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') call
if ($type === 'base64') if ($type === 'base64')
{ {
$type = $charset; $type = $old_type;
$charset = 'us-ascii';
} }
// pass file as resource to Horde_Mime_Part::setContent() // pass file as resource to Horde_Mime_Part::setContent()
@ -358,6 +357,14 @@ class Mailer extends Horde_Mime_Mail
$part = new Horde_Mime_Part(); $part = new Horde_Mime_Part();
$part->setType($type); $part->setType($type);
// set content-type parameters, which get ignored by setType
if (preg_match_all('/;\s*([^=]+)=([^;]*)/', $type, $matches))
{
foreach($matches[1] as $n => $label)
{
$part->setContentTypeParameter($label, $matches[2][$n]);
}
}
$part->setContents($resource); $part->setContents($resource);
// setting name, also sets content-disposition attachment (!), therefore we have to do it after "text/calendar; method=" handling // setting name, also sets content-disposition attachment (!), therefore we have to do it after "text/calendar; method=" handling
@ -365,7 +372,7 @@ class Mailer extends Horde_Mime_Mail
// this should not be necessary, because binary data get detected by mime-type, // this should not be necessary, because binary data get detected by mime-type,
// but at least Cyrus complains about NUL characters // but at least Cyrus complains about NUL characters
$part->setTransferEncoding('base64', array('send' => true)); if (substr($type, 0, 5) != 'text/') $part->setTransferEncoding('base64', array('send' => true));
$part->setDisposition('attachment'); $part->setDisposition('attachment');
return $this->addMimePart($part); return $this->addMimePart($part);

View File

@ -2264,7 +2264,11 @@ class calendar_ical extends calendar_boupdate
$events = array(); $events = array();
$vcal = new Horde_Icalendar; $vcal = new Horde_Icalendar;
if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset)) if ($charset && $charset != 'utf-8')
{
$_vcalData = Api\Translation::convert($_vcalData, $charset, 'utf-8');
}
if (!$vcal->parsevCalendar($_vcalData, 'VCALENDAR'))
{ {
if ($this->log) if ($this->log)
{ {

View File

@ -405,7 +405,7 @@ class infolog_ical extends infolog_bo
foreach((array)$value as $compvData) foreach((array)$value as $compvData)
{ {
$comp = Horde_Icalendar::newComponent(substr($name,3), $vevent); $comp = Horde_Icalendar::newComponent(substr($name,3), $vevent);
$comp->parsevCalendar($compvData,substr($name,3),'utf-8'); $comp->parsevCalendar($compvData,substr($name,3));
$vevent->addComponent($comp); $vevent->addComponent($comp);
} }
} }
@ -654,7 +654,11 @@ class infolog_ical extends infolog_bo
} }
$vcal = new Horde_Icalendar; $vcal = new Horde_Icalendar;
if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR', $charset))) if ($charset && $charset != 'utf-8')
{
$_vcalData = Api\Translation::convert($_vcalData, $charset, 'utf-8');
}
if (!($vcal->parsevCalendar($_vcalData, 'VCALENDAR')))
{ {
if ($this->log) if ($this->log)
{ {
@ -1096,7 +1100,11 @@ class infolog_ical extends infolog_bo
case 'text/x-vnote': case 'text/x-vnote':
$vnote = new Horde_Icalendar; $vnote = new Horde_Icalendar;
if (!$vnote->parsevCalendar($_data, 'VCALENDAR', $charset)) return false; if ($charset && $charset != 'utf-8')
{
$_data = Api\Translation::convert($_data, $charset, 'utf-8');
}
if (!$vnote->parsevCalendar($_data, 'VCALENDAR')) return false;
$components = $vnote->getComponent(); $components = $vnote->getComponent();
foreach ($components as $component) foreach ($components as $component)

View File

@ -913,6 +913,11 @@ class mail_compose
{ {
$name .= '.'.mime_magic::mime2ext($type); $name .= '.'.mime_magic::mime2ext($type);
} }
// use type specified by caller, if Vfs reports only default, or contains specified type (eg. "text/vcard; charset=utf-8")
if (!empty($types[$k]) && ($type == 'application/octet-stream' || stripos($types[$k], $type) === 0))
{
$type = $types[$k];
}
$path = str_replace('+','%2B',$path); $path = str_replace('+','%2B',$path);
$formData = array( $formData = array(
'name' => $name, 'name' => $name,

View File

@ -2383,7 +2383,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
$eventid = $calendar_ical->search($attachment['attachment'],-1); $eventid = $calendar_ical->search($attachment['attachment'],-1);
//error_log(__METHOD__.array2string($eventid)); //error_log(__METHOD__.array2string($eventid));
if (!$eventid) $eventid = -1; if (!$eventid) $eventid = -1;
$event = $calendar_ical->importVCal($attachment['attachment'],(is_array($eventid)?$eventid[0]:$eventid),null,true); $event = $calendar_ical->importVCal($attachment['attachment'],(is_array($eventid)?$eventid[0]:$eventid),null,true,0,'',null,$attachment['charset']);
//error_log(__METHOD__.$event); //error_log(__METHOD__.$event);
if ((int)$event > 0) if ((int)$event > 0)
{ {
@ -2401,7 +2401,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
// double \r\r\n seems to end a vcard prematurely, so we set them to \r\n // double \r\r\n seems to end a vcard prematurely, so we set them to \r\n
//error_log(__METHOD__.__LINE__.$attachment['attachment']); //error_log(__METHOD__.__LINE__.$attachment['attachment']);
$attachment['attachment'] = str_replace("\r\r\n", "\r\n", $attachment['attachment']); $attachment['attachment'] = str_replace("\r\r\n", "\r\n", $attachment['attachment']);
$vcard = $addressbook_vcal->vcardtoegw($attachment['attachment']); $vcard = $addressbook_vcal->vcardtoegw($attachment['attachment'], $attachment['charset']);
if ($vcard['uid']) if ($vcard['uid'])
{ {
$vcard['uid'] = trim($vcard['uid']); $vcard['uid'] = trim($vcard['uid']);
@ -2412,7 +2412,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2);
// if there are not enough fields in the vcard (or the parser was unable to correctly parse the vcard (as of VERSION:3.0 created by MSO)) // if there are not enough fields in the vcard (or the parser was unable to correctly parse the vcard (as of VERSION:3.0 created by MSO))
if ($contact || count($vcard)>2) if ($contact || count($vcard)>2)
{ {
$contact = $addressbook_vcal->addVCard($attachment['attachment'],(is_array($contact)?array_shift($contact):$contact),true); $contact = $addressbook_vcal->addVCard($attachment['attachment'],(is_array($contact)?array_shift($contact):$contact),true,$attachment['charset']);
} }
if ((int)$contact > 0) if ((int)$contact > 0)
{ {