diff --git a/include/class.thread.php b/include/class.thread.php
index 367ed530bee7390d71e16dd2a2f77917c9cb9b33..7ce4ec4035a761433234702c64d5f9b29f61f97c 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -140,7 +140,7 @@ class Thread {
         $entries = array();
         if(($res=db_query($sql)) && db_num_rows($res)) {
             while($rec=db_fetch_array($res)) {
-                $rec['body'] = new ThreadBody($rec['body'], $rec['format']);
+                $rec['body'] = ThreadBody::fromFormattedText($rec['body'], $rec['format']);
                 $entries[] = $rec;
             }
         }
@@ -308,7 +308,7 @@ Class ThreadEntry {
     }
 
     function getBody() {
-        return $this->ht['body'];
+        return ThreadBody::fromFormattedText($this->ht['body'], $this->ht['format']);
     }
 
     function setBody($body) {
@@ -770,7 +770,7 @@ Class ThreadEntry {
     /* variables */
 
     function __toString() {
-        return $this->getBody();
+        return (string) $this->getBody();
     }
 
     function asVar() {
@@ -1002,7 +1002,7 @@ Class ThreadEntry {
             }
         }
 
-        if (!($body = (string) $vars['body']))
+        if (!($body = $vars['body']->getClean()))
             $body = '-'; //Special tag used to signify empty message as stored.
 
         $poster = $vars['poster'];
@@ -1259,36 +1259,23 @@ class ThreadBody /* extends SplString */ {
     var $type;
     var $stripped_images = array();
     var $embedded_images = array();
+    var $options = array(
+        'strip-embedded' => true
+    );
 
-    function __construct($body, $type='text') {
+    function __construct($body, $type='text', $options=array()) {
         $type = strtolower($type);
         if (!in_array($type, static::$types))
             throw new Exception($type.': Unsupported ThreadBody type');
         $this->body = (string) $body;
         $this->type = $type;
+        $this->options = array_merge($this->options, $options);
     }
 
     function isEmpty() {
         return !$this->body || $this->body == '-';
     }
 
-    function display($output=false) {
-        if ($this->isEmpty())
-            return '(empty)';
-
-        switch (strtolower($this->type)) {
-        case 'text':
-            return '<div style="white-space:pre-wrap">'.$this->body.'</div>';
-        case 'html':
-            switch ($output) {
-            case 'pdf':
-                return Format::clickableurls($this->body, false);
-            default:
-                return Format::display($this->body);
-            }
-        }
-    }
-
     function convertTo($type) {
         if ($type === $this->type)
             return $this;
@@ -1340,21 +1327,58 @@ class ThreadBody /* extends SplString */ {
         return $this->type;
     }
 
+    function getClean() {
+        return trim($this->body);
+    }
+
     function __toString() {
-        return $this->body;
+        return $this->display();
+    }
+
+    function toHtml() {
+        return $this->display('html');
+    }
+
+    static function fromFormattedText($text, $format=false) {
+        switch ($format) {
+        case 'text':
+            return new TextThreadBody($text);
+        case 'html':
+            return new HtmlThreadBody($text, array('strip-embedded'=>false));
+        default:
+            return new ThreadBody($text);
+        }
     }
 }
 
 class TextThreadBody extends ThreadBody {
-    function __construct($body) {
-        parent::__construct(Format::stripEmptyLines($body), 'text');
+    function __construct($body, $options=array()) {
+        parent::__construct($body, 'text', $options);
+    }
+
+    function getClean() {
+        return Format::stripEmptyLines($this->body);
+    }
+
+    function display($output=false) {
+        if ($this->isEmpty())
+            return '(empty)';
+
+        switch ($output) {
+        case 'html':
+            return '<div style="white-space:pre-wrap">'.$this->body.'</div>';
+        case 'pdf':
+            return nl2br($this->body);
+        default:
+            return '<pre>'.$this->body.'</pre>';
+        }
     }
 }
 class HtmlThreadBody extends ThreadBody {
-    function __construct($body) {
-        $body = $this->extractEmbeddedHtmlImages($body);
-        $body = trim($body, " <>br/\t\n\r") ? Format::safe_html($body) : '';
-        parent::__construct($body, 'html');
+    function __construct($body, $options=array()) {
+        parent::__construct($body, 'html', $options);
+        if ($this->options['strip-embedded'])
+            $this->body = $this->extractEmbeddedHtmlImages($this->body);
     }
 
     function extractEmbeddedHtmlImages($body) {
@@ -1370,8 +1394,20 @@ class HtmlThreadBody extends ThreadBody {
         }, $body);
     }
 
-    function __toString() {
-        return Format::sanitize($this->body);
+    function getClean() {
+        return trim($body, " <>br/\t\n\r") ? Format::sanitize($body) : '';
+    }
+
+    function display($output=false) {
+        if ($this->isEmpty())
+            return '(empty)';
+
+        switch ($output) {
+        case 'pdf':
+            return Format::clickableurls($this->body, false);
+        default:
+            return Format::display($this->body);
+        }
     }
 }
 ?>
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index 8f61eea8e443fb061d8b706bc565e63bb67915ce..deaa097d9a92692728e0fe5fb3eddb49b2a27581 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -110,7 +110,7 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) {
         ?>
         <table class="thread-entry <?php echo $threadType[$entry['thread_type']]; ?>" cellspacing="0" cellpadding="1" width="800" border="0">
             <tr><th><?php echo Format::db_datetime($entry['created']); ?> &nbsp;&nbsp;<span class="textra"></span><span><?php echo $poster; ?></span></th></tr>
-            <tr><td class="thread-body"><div><?php echo $entry['body']->display(); ?></div></td></tr>
+            <tr><td class="thread-body"><div><?php echo $entry['body']->toHtml(); ?></div></td></tr>
             <?php
             if($entry['attachments']
                     && ($tentry=$ticket->getThreadEntry($entry['id']))
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index eee9fe1cc059f95e232a636e2e286501aa11df30..f885a7ceff0e3ae2aa1307e9d93e0695137d6408 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -362,7 +362,7 @@ $tcount+= $ticket->getNumNotes();
             </tr>
             <tr><td colspan="4" class="thread-body" id="thread-id-<?php
                 echo $entry['id']; ?>"><div><?php
-                echo $entry['body']->display(); ?></div></td></tr>
+                echo $entry['body']->toHtml(); ?></div></td></tr>
             <?php
             if($entry['attachments']
                     && ($tentry = $ticket->getThreadEntry($entry['id']))