diff --git a/inc/email_functions.inc.php b/inc/email_functions.inc.php
index db4599c1..9a1581f0 100644
--- a/inc/email_functions.inc.php
+++ b/inc/email_functions.inc.php
@@ -666,11 +666,20 @@ function hesk_processMessage($msg, $ticket, $is_admin, $is_ticket, $just_message
$msg = str_replace('%%SITE_URL%%', $hesk_settings['site_url'], $msg);
if (isset($ticket['message'])) {
+ // If HTML is enabled, let's unescape everything, and call html2text.
if ($isForHtml) {
$htmlMessage = nl2br($ticket['message']);
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $htmlMessage, $msg);
return str_replace('%%MESSAGE%%', $htmlMessage, $msg);
}
+ $message_has_html = checkForHtml($ticket);
+ if ($message_has_html) {
+ if (!function_exists('convert_html_to_text')) {
+ require(HESK_PATH . 'inc/html2text/html2text.php');
+ }
+ $ticket['message'] = convert_html_to_text($ticket['message']);
+ $ticket['message'] = fix_newlines($ticket['message']);
+ }
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $ticket['message'], $msg);
return str_replace('%%MESSAGE%%', $ticket['message'], $msg);
} else {
@@ -741,6 +750,7 @@ function hesk_processMessage($msg, $ticket, $is_admin, $is_ticket, $just_message
}
}
+
// Is message tag in email template?
if (strpos($msg, '%%MESSAGE%%') !== false) {
// Replace message
@@ -748,7 +758,16 @@ function hesk_processMessage($msg, $ticket, $is_admin, $is_ticket, $just_message
$htmlMessage = nl2br($ticket['message']);
$msg = str_replace('%%MESSAGE%%', $htmlMessage, $msg);
} else {
- $msg = str_replace('%%MESSAGE%%', $ticket['message'], $msg);
+ $plainTextMessage = $ticket['message'];
+ $message_has_html = checkForHtml($ticket);
+ if ($message_has_html) {
+ if (!function_exists('convert_html_to_text')) {
+ require(HESK_PATH . 'inc/html2text/html2text.php');
+ }
+ $plainTextMessage = convert_html_to_text($plainTextMessage);
+ $plainTextMessage = fix_newlines($plainTextMessage);
+ }
+ $msg = str_replace('%%MESSAGE%%', $plainTextMessage, $msg);
}
// Add direct links to any attachments at the bottom of the email message OR add them as attachments, depending on the settings
@@ -823,3 +842,14 @@ function processDirectAttachments($emailMethod, $postfields = NULL, $boundary =
return $attachments;
}
}
+
+function checkForHtml($ticket) {
+ global $hesk_settings;
+
+ $repliesRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto` = ".intval($ticket['id']) . " ORDER BY `id` DESC LIMIT 1");
+ if (hesk_dbNumRows($repliesRs) != 1) {
+ return $ticket['html'];
+ }
+ $reply = hesk_dbFetchAssoc($repliesRs);
+ return $reply['html'];
+}
\ No newline at end of file
diff --git a/inc/html2text/html2text.php b/inc/html2text/html2text.php
new file mode 100755
index 00000000..f3afbef6
--- /dev/null
+++ b/inc/html2text/html2text.php
@@ -0,0 +1,32 @@
+In particular, it tries to maintain the following features:
+ *
+ * - Links are maintained, with the 'href' copied over
+ *
- Information in the <head> is lost
+ *
+ *
+ * @param string html the input HTML
+ * @return string the HTML converted, as best as possible, to text
+ * @throws Html2TextException if the HTML could not be loaded as a {@link DOMDocument}
+ */
+ static function convert($html) {
+ // replace with spaces
+ $html = str_replace(" ", " ", $html);
+
+ $html = static::fixNewlines($html);
+
+ $doc = new \DOMDocument();
+ if (!$doc->loadHTML($html)) {
+ throw new Html2TextException("Could not load HTML - badly formed?", $html);
+ }
+
+ $output = static::iterateOverNode($doc);
+
+ // remove leading and trailing spaces on each line
+ $output = preg_replace("/[ \t]*\n[ \t]*/im", "\n", $output);
+
+ // remove leading and trailing whitespace
+ $output = trim($output);
+
+ return $output;
+ }
+
+ /**
+ * Unify newlines; in particular, \r\n becomes \n, and
+ * then \r becomes \n. This means that all newlines (Unix, Windows, Mac)
+ * all become \ns.
+ *
+ * @param string text text with any number of \r, \r\n and \n combinations
+ * @return string the fixed text
+ */
+ static function fixNewlines($text) {
+ // replace \r\n to \n
+ $text = str_replace("\r\n", "\n", $text);
+ // remove \rs
+ $text = str_replace("\r", "\n", $text);
+
+ return $text;
+ }
+
+ static function nextChildName($node) {
+ // get the next child
+ $nextNode = $node->nextSibling;
+ while ($nextNode != null) {
+ if ($nextNode instanceof \DOMElement) {
+ break;
+ }
+ $nextNode = $nextNode->nextSibling;
+ }
+ $nextName = null;
+ if ($nextNode instanceof \DOMElement && $nextNode != null) {
+ $nextName = strtolower($nextNode->nodeName);
+ }
+
+ return $nextName;
+ }
+
+ static function prevChildName($node) {
+ // get the previous child
+ $nextNode = $node->previousSibling;
+ while ($nextNode != null) {
+ if ($nextNode instanceof \DOMElement) {
+ break;
+ }
+ $nextNode = $nextNode->previousSibling;
+ }
+ $nextName = null;
+ if ($nextNode instanceof \DOMElement && $nextNode != null) {
+ $nextName = strtolower($nextNode->nodeName);
+ }
+
+ return $nextName;
+ }
+
+ static function iterateOverNode($node) {
+ if ($node instanceof \DOMText) {
+ // Replace whitespace characters with a space (equivilant to \s)
+ return preg_replace("/[\\t\\n\\f\\r ]+/im", " ", $node->wholeText);
+ }
+ if ($node instanceof \DOMDocumentType) {
+ // ignore
+ return "";
+ }
+
+ $nextName = static::nextChildName($node);
+ $prevName = static::prevChildName($node);
+
+ $name = strtolower($node->nodeName);
+
+ // start whitespace
+ switch ($name) {
+ case "hr":
+ return "------\n";
+
+ case "style":
+ case "head":
+ case "title":
+ case "meta":
+ case "script":
+ // ignore these tags
+ return "";
+
+ case "h1":
+ case "h2":
+ case "h3":
+ case "h4":
+ case "h5":
+ case "h6":
+ case "ol":
+ case "ul":
+ // add two newlines, second line is added below
+ $output = "\n";
+ break;
+
+ case "td":
+ case "th":
+ // add tab char to separate table fields
+ $output = "\t";
+ break;
+
+ case "tr":
+ case "p":
+ case "div":
+ // add one line
+ $output = "\n";
+ break;
+
+ case "li":
+ $output = "- ";
+ break;
+
+ default:
+ // print out contents of unknown tags
+ $output = "";
+ break;
+ }
+
+ // debug
+ //$output .= "[$name,$nextName]";
+
+ if (isset($node->childNodes)) {
+ for ($i = 0; $i < $node->childNodes->length; $i++) {
+ $n = $node->childNodes->item($i);
+
+ $text = static::iterateOverNode($n);
+
+ $output .= $text;
+ }
+ }
+
+ // end whitespace
+ switch ($name) {
+ case "style":
+ case "head":
+ case "title":
+ case "meta":
+ case "script":
+ // ignore these tags
+ return "";
+
+ case "h1":
+ case "h2":
+ case "h3":
+ case "h4":
+ case "h5":
+ case "h6":
+ $output .= "\n";
+ break;
+
+ case "p":
+ case "br":
+ // add one line
+ if ($nextName != "div")
+ $output .= "\n";
+ break;
+
+ case "div":
+ // add one line only if the next child isn't a div
+ if ($nextName != "div" && $nextName != null)
+ $output .= "\n";
+ break;
+
+ case "a":
+ // links are returned in [text](link) format
+ $href = $node->getAttribute("href");
+ if ($href == null) {
+ // it doesn't link anywhere
+ if ($node->getAttribute("name") != null) {
+ $output = "[$output]";
+ }
+ } else {
+ if ($href == $output || $href == "mailto:$output" || $href == "http://$output" || $href == "https://$output") {
+ // link to the same address: just use link
+ $output;
+ } else {
+ // replace it
+ $output = "[$output]($href)";
+ }
+ }
+
+ // does the next node require additional whitespace?
+ switch ($nextName) {
+ case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
+ $output .= "\n";
+ break;
+ }
+ break;
+
+ case "li":
+ $output .= "\n";
+ break;
+
+ default:
+ // do nothing
+ }
+
+ return $output;
+ }
+
+}
diff --git a/inc/html2text/src/Html2TextException.php b/inc/html2text/src/Html2TextException.php
new file mode 100755
index 00000000..ddfa8658
--- /dev/null
+++ b/inc/html2text/src/Html2TextException.php
@@ -0,0 +1,28 @@
+more_info = $more_info;
+ }
+}
diff --git a/inc/posting_functions.inc.php b/inc/posting_functions.inc.php
index 3bc629a7..bc4559d7 100644
--- a/inc/posting_functions.inc.php
+++ b/inc/posting_functions.inc.php
@@ -168,7 +168,8 @@ function hesk_newTicket($ticket, $isVerified = true)
'dt' => hesk_date(),
'lastchange' => hesk_date(),
'id' => hesk_dbInsertID(),
- 'language' => $language
+ 'language' => $language,
+ 'html' => $ticket['html']
);
// Add custom fields to the array
diff --git a/install/mods-for-hesk/sql/uninstallSql.php b/install/mods-for-hesk/sql/uninstallSql.php
index a330eeef..bc95edb9 100644
--- a/install/mods-for-hesk/sql/uninstallSql.php
+++ b/install/mods-for-hesk/sql/uninstallSql.php
@@ -81,6 +81,8 @@ function removeOtherColumns()
executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` DROP COLUMN `html`");
executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "stage_tickets` DROP COLUMN `html`");
executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` DROP COLUMN `html`");
+ executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "std_replies` DROP COLUMN `html`");
+ executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "ticket_templates` DROP COLUMN `html`");
// These queries are ran in case someone used an unfortunate installation they may have not properly cleaned up tables