Skip to content
Snippets Groups Projects
Commit 83622363 authored by Jared Hancock's avatar Jared Hancock
Browse files

Merge pull request #508 from protich/feature/thread-body-revisited


Thread body revisited

Reviewed-By: default avatarJared Hancock <jared@osticket.com>
parents e0c7e4b6 9b9c4cc6
No related branches found
No related tags found
No related merge requests found
......@@ -337,20 +337,12 @@ class ApiXmlDataParser extends XmlDataParser {
}
if (isset($value['encoding']))
$value['body'] = Format::utf8encode($value['body'], $value['encoding']);
// HTML-ize text if html is enabled
if ($cfg->isHtmlThreadEnabled()
&& (!isset($value['type'])
|| strcasecmp($value['type'], 'text/html')))
$value = sprintf('<pre>%s</pre>',
Format::htmlchars($value['body']));
// Text-ify html if html is disabled
elseif (!$cfg->isHtmlThreadEnabled()
&& !strcasecmp($value['type'], 'text/html'))
$value = Format::html2text(Format::safe_html(
$value['body']), 100, false);
// Noop if they content-type matches the html setting
if (!strcasecmp($value['type'], 'text/html'))
$value = new HtmlThreadBody($value['body']);
else
$value = $value['body'];
$value = new TextThreadBody($value['body']);
} else if ($key == "attachments") {
if(!isset($value['file'][':text']))
$value = $value['file'];
......@@ -390,11 +382,12 @@ class ApiJsonDataParser extends JsonDataParser {
} elseif ($key == "message") {
// Allow message specified in RFC 2397 format
$data = Format::parseRfc2397($value, 'utf-8');
if (!isset($data['type']) || $data['type'] != 'text/html')
$value = sprintf('<pre>%s</pre>',
Format::htmlchars($data['data']));
if (isset($data['type']) && $data['type'] == 'text/html')
$value = new HtmlThreadBody($data['data']);
else
$value = $data['data'];
$value = new TextThreadBody($data['data']);
} else if ($key == "attachments") {
foreach ($value as &$info) {
$data = reset($info);
......@@ -408,10 +401,8 @@ class ApiJsonDataParser extends JsonDataParser {
}
unset($info);
}
if (is_array($value)) {
$value = $this->fixup($value);
}
}
unset($value);
return $current;
}
......@@ -432,9 +423,6 @@ class ApiEmailDataParser extends EmailDataParser {
$data['source'] = 'Email';
if(!$data['message'])
$data['message'] = '--';
if(!$data['subject'])
$data['subject'] = '[No Subject]';
......
......@@ -472,10 +472,8 @@ class MailFetcher {
foreach ($struct->parameters as $p) {
if (strtolower($p->attribute) == 'report-type'
&& $p->value == 'delivery-status') {
return sprintf('<pre>%s</pre>',
Format::htmlchars(
$this->getPart($mid, 'text/plain', $this->charset, $struct, false, 1)
));
return new TextThreadBody( $this->getPart(
$mid, 'text/plain', $this->charset, $struct, false, 1));
}
}
}
......@@ -501,27 +499,23 @@ class MailFetcher {
global $cfg;
if ($cfg->isHtmlThreadEnabled()) {
if ($body=$this->getPart($mid, 'text/html', $this->charset)) {
//Cleanup the html.
$body = (trim($body, " <>br/\t\n\r"))
? Format::safe_html($body)
: '--';
}
elseif ($body=$this->getPart($mid, 'text/plain', $this->charset)) {
$body = trim($body)
? sprintf('<pre>%s</pre>',
Format::htmlchars($body))
: '--';
}
}
else {
if (!($body=$this->getPart($mid, 'text/plain', $this->charset))) {
if ($body=$this->getPart($mid, 'text/html', $this->charset)) {
$body = Format::html2text(Format::safe_html($body), 100, false);
}
}
$body = trim($body) ? $body : '--';
if ($html=$this->getPart($mid, 'text/html', $this->charset))
$body = new HtmlThreadBody($html);
elseif ($text=$this->getPart($mid, 'text/plain', $this->charset))
$body = new TextThreadBody($text);
}
elseif ($text=$this->getPart($mid, 'text/plain', $this->charset))
$body = new TextThreadBody($text);
elseif ($html=$this->getPart($mid, 'text/html', $this->charset))
$body = new TextThreadBody(
Format::html2text(Format::safe_html($html),
100, false));
else
$body = new TextThreadBody('');
if ($cfg->stripQuotedReply())
$body->stripQuotedReply($cfg->getReplySeparator());
return $body;
}
......@@ -572,7 +566,7 @@ class MailFetcher {
$vars['thread-type'] = 'N';
}
else {
$vars['message'] = Format::stripEmptyLines($this->getBody($mid));
$vars['message'] = $this->getBody($mid);
}
......
......@@ -229,27 +229,23 @@ class Mail_Parse {
global $cfg;
if ($cfg->isHtmlThreadEnabled()) {
if ($body=$this->getPart($this->struct,'text/html')) {
// Cleanup the html -- Balance html tags & neutralize unsafe tags.
$body = (trim($body, " <>br/\t\n\r"))
? Format::safe_html($body)
: '--';
}
elseif ($body=$this->getPart($this->struct,'text/plain')) {
$body = trim($body)
? sprintf('<pre>%s</pre>',
Format::htmlchars($body))
: '--';
}
}
else {
if (!($body=$this->getPart($this->struct,'text/plain'))) {
if ($body=$this->getPart($this->struct,'text/html')) {
$body = Format::html2text(Format::safe_html($body), 100, false);
}
}
$body = trim($body) ? $body : '--';
if ($html=$this->getPart($this->struct,'text/html'))
$body = new HtmlThreadBody($html);
elseif ($text=$this->getPart($this->struct,'text/plain'))
$body = new TextThreadBody($text);
}
elseif ($text=$this->getPart($this->struct,'text/plain'))
$body = new TextThreadBody($text);
elseif ($html=$this->getPart($this->struct,'text/html'))
$body = new TextThreadBody(
Format::html2text(Format::safe_html($html),
100, false));
else
$body = new TextThreadBody('');
if ($cfg->stripQuotedReply())
$body->stripQuotedReply($cfg->getReplySeparator());
return $body;
}
......@@ -481,7 +477,7 @@ class EmailDataParser {
}
else {
// Typical email
$data['message'] = Format::stripEmptyLines($parser->getBody());
$data['message'] = $parser->getBody();
$data['in-reply-to'] = $parser->struct->headers['in-reply-to'];
$data['references'] = $parser->struct->headers['references'];
}
......
......@@ -865,23 +865,17 @@ Class ThreadEntry {
if(!$vars['ticketId'] || !$vars['type'] || !in_array($vars['type'], array('M','R','N')))
return false;
//Strip quoted reply...on emailed messages
if($vars['origin']
&& !strcasecmp($vars['origin'], 'Email')
&& $cfg->stripQuotedReply()
&& ($tag=$cfg->getReplySeparator())
&& strpos($vars['body'], $tag))
if((list($msg) = explode($tag, $vars['body'], 2)) && trim($msg))
$vars['body'] = $msg;
if (!$cfg->isHtmlThreadEnabled()) {
// Data in the database is assumed to be HTML, change special
// plain text XML characters
$vars['title'] = Format::htmlchars($vars['title']);
$vars['body'] = sprintf('<pre>%s</pre>',
Format::htmlchars($vars['body']));
if (!$vars['body'] instanceof ThreadBody) {
if ($cfg->isHtmlThreadEnabled())
$vars['body'] = new HtmlThreadBody($vars['body']);
else
$vars['body'] = new TextThreadBody($vars['body']);
}
$vars['body'] = Format::sanitize($vars['body']);
if (!($body = Format::sanitize(
(string) $vars['body']->convertTo('html'))))
$body = '-'; //Special tag used to signify empty message as stored.
$poster = $vars['poster'];
if ($poster && is_object($poster))
......@@ -899,7 +893,7 @@ Class ThreadEntry {
if (!isset($vars['attachments']) || !$vars['attachments'])
// Otherwise, body will be configured in a block below (after
// inline attachments are saved and updated in the database)
$sql.=' ,body='.db_input($vars['body']);
$sql.=' ,body='.db_input($body);
if(isset($vars['pid']))
$sql.=' ,pid='.db_input($vars['pid']);
......@@ -936,12 +930,12 @@ Class ThreadEntry {
// content-id will be discarded, only the unique hash-code
// will be available to retrieve the image later
if ($a['cid'] && $a['key']) {
$vars['body'] = str_replace('src="cid:'.$a['cid'].'"',
'src="cid:'.$a['key'].'"', $vars['body']);
$body = str_replace('src="cid:'.$a['cid'].'"',
'src="cid:'.$a['key'].'"', $body);
}
}
unset($a);
$sql = 'UPDATE '.TICKET_THREAD_TABLE.' SET body='.db_input($vars['body'])
$sql = 'UPDATE '.TICKET_THREAD_TABLE.' SET body='.db_input($body)
.' WHERE `id`='.db_input($entry->getId());
if (!db_query($sql) || !db_affected_rows())
return false;
......@@ -954,7 +948,7 @@ Class ThreadEntry {
$entry->saveEmailInfo($vars);
// Inline images (attached to the draft)
$entry->saveAttachments(Draft::getAttachmentIds($vars['body']));
$entry->saveAttachments(Draft::getAttachmentIds($body));
return $entry;
}
......@@ -1123,4 +1117,61 @@ class Note extends ThreadEntry {
)?$n:null;
}
}
class ThreadBody /* extends SplString */ {
static $types = array('text', 'html');
var $body;
var $type;
function __construct($body, $type='text') {
$type = strtolower($type);
if (!in_array($type, static::$types))
throw new Exception($type.': Unsupported ThreadBody type');
$this->body = (string) $body;
$this->type = $type;
}
function convertTo($type) {
if ($type === $this->type)
return $this;
$conv = $this->type . ':' . strtolower($type);
switch ($conv) {
case 'text:html':
return new ThreadBody(sprintf('<pre>%s</pre>',
Format::htmlchars($this->body)), $type);
case 'html:text':
return new ThreadBody(Format::html2text((string) $this), $type);
}
}
function stripQuotedReply($tag) {
//Strip quoted reply...on emailed messages
if (!$tag || strpos($this->body, $tag) === false)
return;
if ((list($msg) = explode($tag, $this->body, 2)) && trim($msg))
$this->body = $msg;
}
function __toString() {
return $this->body;
}
}
class TextThreadBody extends ThreadBody {
function __construct($body) {
parent::__construct(Format::stripEmptyLines($body), 'text');
}
}
class HtmlThreadBody extends ThreadBody {
function __construct($body) {
$body = trim($body, " <>br/\t\n\r") ? Format::safe_html($body) : '';
parent::__construct($body, 'html');
}
}
?>
......@@ -1752,11 +1752,19 @@ class Ticket {
function logNote($title, $note, $poster='SYSTEM', $alert=true) {
$errors = array();
//Unless specified otherwise, assume HTML
if ($note && is_string($note))
$note = new HtmlThreadBody($note);
return $this->postNote(
array('title' => $title, 'note' => $note),
array(
'title' => $title,
'note' => $note,
),
$errors,
$poster,
$alert);
$alert
);
}
function postNote($vars, &$errors, $poster, $alert=true) {
......@@ -2164,7 +2172,7 @@ class Ticket {
$id=0;
$fields=array();
$fields['message'] = array('type'=>'text', 'required'=>1, 'error'=>'Message required');
$fields['message'] = array('type'=>'*', 'required'=>1, 'error'=>'Message required');
switch (strtolower($origin)) {
case 'web':
$fields['topicId'] = array('type'=>'int', 'required'=>1, 'error'=>'Select help topic');
......
......@@ -61,6 +61,10 @@ class Validator {
$this->errors[$k]=$field['error'];
continue;
}
//We don't care about the type.
if ($field['type'] == '*') continue;
//Do the actual validation based on the type.
switch(strtolower($field['type'])):
case 'integer':
......@@ -73,7 +77,7 @@ class Validator {
case 'double':
if(!is_numeric($this->input[$k]))
$this->errors[$k]=$field['error'];
break;
break;
case 'text':
case 'string':
if(!is_string($this->input[$k]))
......@@ -84,9 +88,9 @@ class Validator {
$this->errors[$k]=$field['error'];
break;
case 'radio':
if(!isset($this->input[$k]))
$this->errors[$k]=$field['error'];
break;
if(!isset($this->input[$k]))
$this->errors[$k]=$field['error'];
break;
case 'date': //TODO...make sure it is really in GNU date format..
if(strtotime($this->input[$k])===false)
$this->errors[$k]=$field['error'];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment