diff --git a/include/class.ticket.php b/include/class.ticket.php
index a6bff31c40f5ec4cc24f2434e72828ccde2407c3..d01f438d791c6d5c104a594e65299ac2e5ce2deb 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -75,18 +75,25 @@ class Ticket{
        
         $sql='SELECT  ticket.*, topic.topic as helptopic, lock_id, dept_name, priority_desc '
             .' ,count(attach.attach_id) as attachments '
-            .' ,count(DISTINCT message.msg_id) as messages '
-            .' ,count(DISTINCT response.response_id) as responses '
-            .' ,count(DISTINCT note.note_id) as notes '
+            .' ,count(DISTINCT message.id) as messages '
+            .' ,count(DISTINCT response.id) as responses '
+            .' ,count(DISTINCT note.id) as notes '
             .' FROM '.TICKET_TABLE.' ticket '
             .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '
-            .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.priority_id) '
-            .' LEFT JOIN '.TOPIC_TABLE.' topic ON (ticket.topic_id=topic.topic_id) '
-            .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) '
-            .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) '
-            .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) '
-            .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) '
-            .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) '
+            .' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON ('
+                .'ticket.priority_id=pri.priority_id) '
+            .' LEFT JOIN '.TOPIC_TABLE.' topic ON ('
+                .'ticket.topic_id=topic.topic_id) '
+            .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON ('
+                .'ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW()) '
+            .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON ('
+                .'ticket.ticket_id=attach.ticket_id) '
+            .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON ('
+                ."ticket.ticket_id=message.ticket_id AND message.thread_type = 'M') "
+            .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON ('
+                ."ticket.ticket_id=response.ticket_id AND response.thread_type = 'R') "
+            .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON ( '
+                ."ticket.ticket_id=note.ticket_id AND note.thread_type = 'N') "
             .' WHERE ticket.ticket_id='.db_input($id)
             .' GROUP BY ticket.ticket_id';
 
@@ -436,9 +443,10 @@ class Ticket{
     function getLastRespondent() {
 
         $sql ='SELECT  resp.staff_id '
-             .' FROM '.TICKET_RESPONSE_TABLE.' resp '
+             .' FROM '.TICKET_THREAD_TABLE.' resp '
              .' LEFT JOIN '.STAFF_TABLE. ' USING(staff_id) '
              .' WHERE  resp.ticket_id='.db_input($this->getId()).' AND resp.staff_id>0 '
+             .'   AND  resp.thread_type="R"'
              .' ORDER BY resp.created DESC LIMIT 1';
 
         if(!($res=db_query($sql)) || !db_num_rows($res))
@@ -456,8 +464,9 @@ class Ticket{
             return $this->lastmsgdate;
 
         //for old versions...XXX: still needed????
-        $sql='SELECT created FROM '.TICKET_MESSAGE_TABLE
+        $sql='SELECT created FROM '.TICKET_THREAD_TABLE
             .' WHERE ticket_id='.db_input($this->getId())
+            ."   AND thread_type = 'M'"
             .' ORDER BY created DESC LIMIT 1';
         if(($res=db_query($sql)) && db_num_rows($res))
             list($this->lastmsgdate)=db_fetch_row($res);
@@ -474,8 +483,9 @@ class Ticket{
         if($this->lastrespdate)
             return $this->lastrespdate;
 
-        $sql='SELECT created FROM '.TICKET_RESPONSE_TABLE
+        $sql='SELECT created FROM '.TICKET_THREAD_TABLE
             .' WHERE ticket_id='.db_input($this->getId())
+            .'   AND thread_type="R"'
             .' ORDER BY created DESC LIMIT 1';
         if(($res=db_query($sql)) && db_num_rows($res))
             list($this->lastrespdate)=db_fetch_row($res);
@@ -522,11 +532,12 @@ class Ticket{
             $order='DESC';
 
         $sql ='SELECT note.*, count(DISTINCT attach.attach_id) as attachments '
-            .' FROM '.TICKET_NOTE_TABLE.' note '
+            .' FROM '.TICKET_THREAD_TABLE.' note '
             .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach
-                ON (note.ticket_id=attach.ticket_id AND note.note_id=attach.ref_id AND ref_type="N") '
+                ON (note.ticket_id=attach.ticket_id AND note.id=attach.ref_id AND ref_type="N") '
             .' WHERE note.ticket_id='.db_input($this->getId())
-            .' GROUP BY note.note_id '
+            .'   AND note.thread_type="N"'
+            .' GROUP BY note.id '
             .' ORDER BY note.created '.$order;
 
         $notes=array();
@@ -539,14 +550,17 @@ class Ticket{
 
     function getMessages() {
 
-        $sql='SELECT msg.msg_id, msg.created, msg.message '
-            .' ,count(DISTINCT attach.attach_id) as attachments, count( DISTINCT resp.response_id) as responses '
-            .' FROM '.TICKET_MESSAGE_TABLE.' msg '
-            .' LEFT JOIN '.TICKET_RESPONSE_TABLE. ' resp ON(resp.msg_id=msg.msg_id) '
-            .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach 
-                ON (msg.ticket_id=attach.ticket_id AND msg.msg_id=attach.ref_id AND ref_type="M") '
+        $sql='SELECT msg.id, msg.created, msg.body '
+            .' ,count(DISTINCT attach.attach_id) as attachments '
+            .' ,count( DISTINCT resp.id) as responses '
+            .' FROM '.TICKET_THREAD_TABLE.' msg '
+            .' LEFT JOIN '.TICKET_THREAD_TABLE.' resp ON ('
+                .'resp.pid=msg.id AND resp.thread_type = "R") '
+            .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach '
+                .'ON (msg.ticket_id=attach.ticket_id AND msg.id=attach.ref_id AND ref_type="M") '
             .' WHERE  msg.ticket_id='.db_input($this->getId())
-            .' GROUP BY msg.msg_id '
+               .' AND msg.thread_type="M"'
+            .' GROUP BY msg.id '
             .' ORDER BY msg.created ASC ';
 
         $messages=array();
@@ -560,11 +574,12 @@ class Ticket{
     function getResponses($msgId) {
 
         $sql='SELECT resp.*, count(DISTINCT attach.attach_id) as attachments '
-            .' FROM '.TICKET_RESPONSE_TABLE. ' resp '
+            .' FROM '.TICKET_THREAD_TABLE. ' resp '
             .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach 
-                ON (resp.ticket_id=attach.ticket_id AND resp.response_id=attach.ref_id AND ref_type="R") '
+                ON (resp.ticket_id=attach.ticket_id AND resp.id=attach.ref_id AND ref_type="R") '
             .' WHERE  resp.ticket_id='.db_input($this->getId())
-            .' GROUP BY resp.response_id '
+            .'   AND  resp.thread_type="R"'
+            .' GROUP BY resp.id '
             .' ORDER BY resp.created';
 
         $responses=array();
@@ -1272,18 +1287,18 @@ class Ticket{
     }
 
     //Insert message from client
-    function postMessage($msg,$source='',$msgid=NULL,$headers='',$newticket=false){
+    function postMessage($msg,$source='',$emsgid=null,$headers='',$newticket=false){
         global $cfg;
        
         if(!$this->getId()) return 0;
         
         # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder.
 
-        $sql='INSERT INTO '.TICKET_MESSAGE_TABLE.' SET created=NOW() '
+        $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()'
+            .' ,thread_type="M" '
             .' ,ticket_id='.db_input($this->getId())
-            .' ,messageId='.db_input($msgid)
-            .' ,message='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc
-            .' ,headers='.db_input($headers) //Raw header.
+            # XXX: Put Subject header into the 'title' field
+            .' ,body='.db_input(Format::striptags($msg)) //Tags/code stripped...meaning client can not send in code..etc
             .' ,source='.db_input($source?$source:$_SERVER['REMOTE_ADDR'])
             .' ,ip_address='.db_input($_SERVER['REMOTE_ADDR']);
     
@@ -1291,6 +1306,15 @@ class Ticket{
 
         $this->setLastMsgId($msgid);
 
+        if ($emsgid !== null) {
+            $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE
+                .' SET msg_id='.db_input($msgid)
+                .', email_mid='.db_input($emsgid)
+                .', headers='.db_input($headers);
+
+            if (!db_query($sql)) return 0;
+        }
+
         if($newticket) return $msgid; //Our work is done...
 
         $autorespond = true;
@@ -1355,10 +1379,11 @@ class Ticket{
 
         if($errors) return 0;
 
-        $sql='INSERT INTO '.TICKET_RESPONSE_TABLE.' SET created=NOW() '
+        $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() '
+            .' ,thread_type="R"'
             .' ,ticket_id='.db_input($this->getId())
-            .' ,msg_id='.db_input($vars['msgId'])
-            .' ,response='.db_input(Format::striptags($vars['response']))
+            .' ,pid='.db_input($vars['msgId'])
+            .' ,body='.db_input(Format::striptags($vars['response']))
             .' ,staff_id='.db_input($thisstaff->getId())
             .' ,staff_name='.db_input($thisstaff->getName())
             .' ,ip_address='.db_input($thisstaff->getIP());
@@ -1432,7 +1457,7 @@ class Ticket{
         if(!$cfg || !$cfg->logTicketActivity())
             return 0;
 
-        return $this->postNote($title,$note,false,'system');
+        return $this->postNote($title,$note,false,'System');
     }
 
     // History log -- used for statistics generation (pretty reports)
@@ -1459,12 +1484,13 @@ class Ticket{
     function postNote($title,$note,$alert=true,$poster='') {        
         global $thisstaff,$cfg;
 
-        $sql= 'INSERT INTO '.TICKET_NOTE_TABLE.' SET created=NOW() '.
+        $sql= 'INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW() '.
+                ',thread_type="N"'.
                 ',ticket_id='.db_input($this->getId()).
                 ',title='.db_input(Format::striptags($title)).
-                ',note='.db_input(Format::striptags($note)).
+                ',body='.db_input(Format::striptags($note)).
                 ',staff_id='.db_input($thisstaff?$thisstaff->getId():0).
-                ',source='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName());
+                ',poster='.db_input(($poster || !$thisstaff)?$poster:$thisstaff->getName());
         //echo $sql;
         if(!db_query($sql) || !($id=db_insert_id()))
             return false;
@@ -1566,9 +1592,7 @@ class Ticket{
         if(!db_query($sql) || !db_affected_rows())
             return false;
 
-        db_query('DELETE FROM '.TICKET_MESSAGE_TABLE.' WHERE ticket_id='.db_input($this->getId()));
-        db_query('DELETE FROM '.TICKET_RESPONSE_TABLE.' WHERE ticket_id='.db_input($this->getId()));
-        db_query('DELETE FROM '.TICKET_NOTE_TABLE.' WHERE ticket_id='.db_input($this->getId()));
+        db_query('DELETE FROM '.TICKET_THREAD_TABLE.' WHERE ticket_id='.db_input($this->getId()));
         $this->deleteAttachments();
         
         return true;
@@ -1684,8 +1708,9 @@ class Ticket{
             return 0;
 
         $sql='SELECT ticket.ticket_id FROM '.TICKET_TABLE. ' ticket '.
-             ' LEFT JOIN '.TICKET_MESSAGE_TABLE.' msg USING(ticket_id) '.
-             ' WHERE messageId='.db_input($mid).' AND email='.db_input($email);
+             ' LEFT JOIN '.TICKE_THREAD_TABLE.' msg USING(ticket_id) '.
+             ' INNER JOIN '.TICKET_EMAIL_INFO_TABLE.' emsg ON (msg.id = emsg.message_id) '.
+             ' WHERE email_mid='.db_input($mid).' AND email='.db_input($email);
         $id=0;
         if(($res=db_query($sql)) && db_num_rows($res))
             list($id)=db_fetch_row($res);
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
index a360217167bde83dedcb4decb339677e3c5370d6..7719ec74a7ef2a58babcae7112a0d2cb05caa92e 100644
--- a/include/client/tickets.inc.php
+++ b/include/client/tickets.inc.php
@@ -59,13 +59,12 @@ if($search) {
         $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes.
         $qwhere.=' AND ( '
                 ." ticket.subject LIKE '%$queryterm%'"
-                ." OR message.message LIKE '%$queryterm%'"
-                ." OR response.response LIKE '%$queryterm%'"
+                ." OR thread.body LIKE '%$queryterm%'"
                 .' ) ';
         $deep_search=true;
         //Joins needed for search
-        $qfrom.=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )'
-               .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )';
+        $qfrom.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ('
+               .'ticket.ticket_id=thread.ticket_id AND thread.thread_type IN ("M","R"))';
     }
 }
 
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index e720ed96bffa58c5d7321e7fe2544c7829a86678..f67e6d94bd3a4456e30b17797254dff49204b960 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -67,11 +67,11 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) {
         
             <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr>
             
-            <tr><td><?php echo Format::display($message['message']); ?></td></tr>
+            <tr><td><?php echo Format::display($message['body']); ?></td></tr>
             
             <?php
             
-            if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) { ?>
+            if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) { ?>
             
                 <tr><td class="info"><?php echo $links; ?></td></tr>
                 
@@ -81,7 +81,7 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) {
             
         </table>
         <?php
-        if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) {
+        if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) {
            foreach($responses as $resp) {
                $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']);
                ?>
@@ -89,9 +89,9 @@ if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) {
                 <tr>
                     <th><?php echo Format::db_datetime($resp['created']);?>&nbsp;-&nbsp;<?php echo $staff; ?></th>
                 </tr>
-                <tr><td><?php echo Format::display($resp['response']); ?></td></tr>
+                <tr><td><?php echo Format::display($resp['body']); ?></td></tr>
                 <?php
-                if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?>
+                if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?>
                  <tr><td class="info"><?php echo $links; ?></td></tr>
                 <?php
                  }?>
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index 33f46eadd443ccf0cda94867d0e54a924b73e30e..faac0f86ef791a8726c266a8121a980860ddc267 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -196,11 +196,11 @@ if($ticket->isOverdue())
             </tr>
             <tr>
                 <td colspan="2">
-                    <?php echo Format::htmlchars($note['note']); ?>
+                    <?php echo Format::htmlchars($note['body']); ?>
                 </td>
             </tr>
             <?php
-            if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['note_id'],'N'))) {?>
+            if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['id'],'N'))) {?>
             <tr>
                 <td class="info" colspan="2"><?php echo $links; ?></td>
             </tr>
@@ -220,9 +220,9 @@ if($ticket->isOverdue())
        foreach($messages as $message) {?>
         <table class="message" cellspacing="0" cellpadding="1" width="940" border="0">
             <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr>
-            <tr><td><?php echo Format::display($message['message']); ?></td></tr>
+            <tr><td><?php echo Format::display($message['body']); ?></td></tr>
             <?php
-            if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['msg_id'],'M'))) {?>
+            if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) {?>
             <tr>
                 <td class="info"><?php echo $links; ?></td>
             </tr>
@@ -231,17 +231,17 @@ if($ticket->isOverdue())
         </table>
         <?php
         /* --------- Responses ------------ */
-        if($message['responses'] && ($responses=$ticket->getResponses($message['msg_id']))) {
+        if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) {
            foreach($responses as $resp) {?>
             <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0">
                 <tr>
                     <th><?php echo Format::db_datetime($resp['created']); ?>&nbsp;-&nbsp;<?php echo Format::htmlchars($resp['staff_name']); ?></th>
                 </tr>
                 <tr>
-                    <td><?php echo Format::display($resp['response']); ?></td>
+                    <td><?php echo Format::display($resp['body']); ?></td>
                 </tr>
                 <?php
-                if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['response_id'],'R'))) {?>
+                if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?>
                 <tr>
                     <td class="info"><?php echo $links; ?></td>
                 </tr>
@@ -251,7 +251,7 @@ if($ticket->isOverdue())
             <?php
            }
         }
-        $msgId=$message['msg_id'];
+        $msgId=$message['id'];
        }
     } else {
         echo '<p>Error fetching ticket thread - get technical help.</p>';
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index c60bdc75059febe417307e4a77d45dca73739022..f11cf681c7dc6af352aeb57285f21ce86437009e 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -105,6 +105,8 @@ if($search):
         if(is_numeric($searchTerm)){
             $qwhere.=" AND ticket.ticketID LIKE '$queryterm%'";
         }elseif(strpos($searchTerm,'@') && Validator::is_email($searchTerm)){ //pulling all tricks!
+            # XXX: What about searching for email addresses in the body of
+            #      the thread message
             $qwhere.=" AND ticket.email='$queryterm'";
         }else{//Deep search!
             //This sucks..mass scan! search anything that moves! 
@@ -114,19 +116,15 @@ if($search):
                 $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'".
                             " OR ticket.name LIKE '%$queryterm%'".
                             " OR ticket.subject LIKE '%$queryterm%'".
-                            " OR note.title LIKE '%$queryterm%'".
-                            " OR MATCH(message.message)   AGAINST('$queryterm')".
-                            " OR MATCH(response.response) AGAINST('$queryterm')".
-                            " OR MATCH(note.note) AGAINST('$queryterm')".
+                            " OR thread.title LIKE '%$queryterm%'".
+                            " OR MATCH(thread.body)   AGAINST('$queryterm')".
                             ' ) ';
             }else{
                 $qwhere.=" AND ( ticket.email LIKE '%$queryterm%'".
                             " OR ticket.name LIKE '%$queryterm%'".
                             " OR ticket.subject LIKE '%$queryterm%'".
-                            " OR message.message LIKE '%$queryterm%'".
-                            " OR response.response LIKE '%$queryterm%'".
-                            " OR note.note LIKE '%$queryterm%'".
-                            " OR note.title LIKE '%$queryterm%'".
+                            " OR thread.body LIKE '%$queryterm%'".
+                            " OR thread.title LIKE '%$queryterm%'".
                             ' ) ';
             }
         }
@@ -203,9 +201,7 @@ $qfrom=' FROM '.TICKET_TABLE.' ticket '.
 
 $sjoin='';
 if($search && $deep_search) {
-    $sjoin=' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id )'
-          .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id )'
-          .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) ';
+    $sjoin=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )';
 }
 
 $qgroup=' GROUP BY ticket.ticket_id';
@@ -219,9 +215,9 @@ $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&ord
 
 //ADD attachment,priorities, lock and other crap
 $qselect.=' ,count(attach.attach_id) as attachments '
-         .' ,count(DISTINCT message.msg_id) as messages '
-         .' ,count(DISTINCT response.response_id) as responses '
-         .' ,count(DISTINCT note.note_id) as notes '
+         .' ,count(DISTINCT message.id) as messages '
+         .' ,count(DISTINCT response.id) as responses '
+         .' ,count(DISTINCT note.id) as notes '
          .' ,IF(ticket.reopened is NULL,IF(ticket.lastmessage is NULL,ticket.created,ticket.lastmessage),ticket.reopened) as effective_date '
          .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team '
          .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned ';
@@ -230,9 +226,12 @@ $qfrom.=' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.pri
        .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW() 
                AND tlock.staff_id!='.db_input($thisstaff->getId()).') '
        .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) '
-       .' LEFT JOIN '.TICKET_MESSAGE_TABLE.' message ON (ticket.ticket_id=message.ticket_id) '
-       .' LEFT JOIN '.TICKET_RESPONSE_TABLE.' response ON (ticket.ticket_id=response.ticket_id) '
-       .' LEFT JOIN '.TICKET_NOTE_TABLE.' note ON (ticket.ticket_id=note.ticket_id ) '
+       .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON ('
+            .'ticket.ticket_id=message.ticket_id AND message.thread_type="M") '
+       .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON ('
+            .'ticket.ticket_id=response.ticket_id AND response.thread_type="R") '
+       .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON ('
+            .'ticket.ticket_id=note.ticket_id AND note.thread_type="N") '
        .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) '
        .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) ';
 
diff --git a/main.inc.php b/main.inc.php
index 7b10c018a69abb54ab321a917889e48fc80c99da..b098bc175a890478dee7c40f99e7a42031ca37f9 100644
--- a/main.inc.php
+++ b/main.inc.php
@@ -135,9 +135,7 @@
     define('CANNED_ATTACHMENT_TABLE',TABLE_PREFIX.'canned_attachment');
 
     define('TICKET_TABLE',TABLE_PREFIX.'ticket');
-    define('TICKET_NOTE_TABLE',TABLE_PREFIX.'ticket_note');
-    define('TICKET_MESSAGE_TABLE',TABLE_PREFIX.'ticket_message');
-    define('TICKET_RESPONSE_TABLE',TABLE_PREFIX.'ticket_response');
+    define('TICKET_THREAD_TABLE',TABLE_PREFIX.'ticket_thread');
     define('TICKET_ATTACHMENT_TABLE',TABLE_PREFIX.'ticket_attachment');
     define('TICKET_PRIORITY_TABLE',TABLE_PREFIX.'ticket_priority');
     define('PRIORITY_TABLE',TICKET_PRIORITY_TABLE);
diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php
index c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5..21b4f33ee6b51a23a1459575e164e0fcfe673c1f 100644
--- a/setup/inc/class.setup.php
+++ b/setup/inc/class.setup.php
@@ -366,9 +366,10 @@ class Installer extends SetupWizard {
             if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt')))
                 $msg='Congratulations and Thank you for choosing osTicket!';
                         
-            $sql='INSERT INTO '.PREFIX.'ticket_message SET created=NOW(),source="Web" '
+            $sql='INSERT INTO '.PREFIX.'ticket_thread SET created=NOW(),source="Web" '
+                .', poster="System"'
                 .', ticket_id='.db_input($tid)
-                .', message='.db_input($msg);
+                .', body='.db_input($msg);
             @mysql_query($sql);
         }
         //TODO: create another personalized ticket and assign to admin??
diff --git a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a5f54aa8516aaaaf268e363b8ae58674725b61af
--- /dev/null
+++ b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql
@@ -0,0 +1,109 @@
+/**
+ * Merge ticket thread tables into one
+ *  
+ * Replace the ticket_{message,response,note} tables with a single
+ * ticket_thread table that will contain data for all three current message
+ * types. This simplifies much of the ticket thread code and paves the way 
+ * for other types of messages in the future.
+ * 
+ * This patch automagically moves the data from the three federated tables
+ * into the one combined table.
+ */
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`;
+CREATE TABLE `%TABLE_PREFIX%ticket_thread` (
+  `id` int(11) unsigned NOT NULL auto_increment,
+  `pid` int(11) unsigned NOT NULL default '0',
+  `ticket_id` int(11) unsigned NOT NULL default '0',
+  `staff_id` int(11) unsigned NOT NULL default '0',
+  `thread_type` enum('M','R','N') NOT NULL,
+  `poster` varchar(128) NOT NULL default '',
+  `source` varchar(32) NOT NULL default '',
+  `title` varchar(255),
+  `body` text NOT NULL,
+  `ip_address` varchar(64) NOT NULL default '',
+  `created` datetime NOT NULL,
+  `updated` datetime NOT NULL,
+  -- Temporary columns for conversion
+  `old_pk` int(11) unsigned NOT NULL,
+  `old_pid` int(11) unsigned,
+  PRIMARY KEY  (`id`),
+  KEY `ticket_id` (`ticket_id`),
+  KEY `staff_id` (`staff_id`),
+  FULLTEXT KEY `body` (`body`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`;
+CREATE TABLE `%TABLE_PREFIX%ticket_email_info` (
+  `message_id` int(11) unsigned NOT NULL,
+  `email_mid` varchar(255) NOT NULL,
+  `headers` text,
+  KEY `message_id` (`email_mid`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
+-- Transfer messages
+INSERT INTO `%TABLE_PREFIX%ticket_thread`
+  (`ticket_id`, `thread_type`, `body`, `ip_address`,
+    `created`, `updated`, `old_pk`)
+  SELECT `ticket_id`, 'M', `message`, `ip_address`,
+    `created`, COALESCE(`updated`, NOW()), `msg_id`
+    FROM `%TABLE_PREFIX%ticket_message`;
+
+-- Transfer responses
+INSERT INTO `%TABLE_PREFIX%ticket_thread`
+  (`ticket_id`, `staff_id`, `thread_type`, `poster`, `body`, `ip_address`,
+    `created`, `updated`, `old_pk`, `old_pid`)
+  SELECT `ticket_id`, `staff_id`, 'R', `staff_name`, `response`, `ip_address`,
+    `created`, COALESCE(`updated`, NOW()), `response_id`, `msg_id` 
+    FROM `%TABLE_PREFIX%ticket_response`;
+
+-- Connect responses to (new) messages
+CREATE TABLE `%TABLE_PREFIX%T_resp_links`
+    SELECT `id`, `old_pk`, `old_pid` FROM `%TABLE_PREFIX%ticket_thread`;
+
+UPDATE `%TABLE_PREFIX%ticket_thread`
+    SET `pid` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%T_resp_links` T2
+                  WHERE `old_pid` = T2.`old_pk` )
+    WHERE `thread_type` = 'R'
+      AND `old_pid` IS NOT NULL;
+
+DROP TABLE `%TABLE_PREFIX%T_resp_links`;
+
+-- Transfer notes
+INSERT INTO `%TABLE_PREFIX%ticket_thread`
+  (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`,
+    `source`, `poster`, `created`, `updated`, `old_pk`)
+  SELECT `ticket_id`, `staff_id`, 'N', `note`, `title`,
+    `source`, ( SELECT CONCAT_WS(' ', T2.`firstname`, T2.`lastname`)
+                FROM `%TABLE_PREFIX%staff` T2
+                WHERE T2.`staff_id` = `staff_id` ),
+    `created`, NOW(), `note_id`
+    FROM `%TABLE_PREFIX%ticket_note`;
+
+-- Transfer email information from messages
+INSERT INTO `%TABLE_PREFIX%ticket_email_info`
+    (`message_id`, `email_mid`, `headers`)
+    SELECT ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2
+             WHERE `msg_id` = T2.`old_pk`
+               AND `thread_type` = 'M' ),
+         `messageId`, `headers`
+    FROM `%TABLE_PREFIX%ticket_message`
+    WHERE `messageId` IS NOT NULL;
+
+-- Update attachment table
+UPDATE `%TABLE_PREFIX%ticket_attachment`
+    SET `ref_id` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2
+                     WHERE `ref_id` = T2.`old_pk`
+                       AND `ref_type` = T2.`thread_type` );
+
+-- Drop temporary columns
+ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pk`;
+ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pid`;
+
+-- Drop old tables
+DROP TABLE `%TABLE_PREFIX%ticket_message`;
+DROP TABLE `%TABLE_PREFIX%ticket_response`;
+DROP TABLE `%TABLE_PREFIX%ticket_note`;
+
+-- Finished with patch
+UPDATE `%TABLE_PREFIX%config`
+    SET `schema_signature`='abe9c0cb845be52c10fcd7b3e626a589';
diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osticket-v1.7-mysql.sql
index 7a31d814e1ad8544066830ad2d5d782aaf2da426..fbd2059bab92027cac455a893689ddc9e80445ca 100644
--- a/setup/inc/sql/osticket-v1.7-mysql.sql
+++ b/setup/inc/sql/osticket-v1.7-mysql.sql
@@ -598,6 +598,14 @@ CREATE TABLE `%TABLE_PREFIX%ticket_lock` (
   KEY `staff_id` (`staff_id`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`;
+CREATE TABLE `%TABLE_PREFIX%ticket_email_info` (
+  `message_id` int(11) unsigned NOT NULL,
+  `email_mid` varchar(255) NOT NULL,
+  `headers` text,
+  KEY `message_id` (`email_mid`)
+) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+
 DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`;
 CREATE TABLE `%TABLE_PREFIX%ticket_event` (
   `ticket_id` int(11) unsigned NOT NULL default '0',
@@ -612,38 +620,6 @@ CREATE TABLE `%TABLE_PREFIX%ticket_event` (
   KEY `ticket_stats` (`timestamp`, `state`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_message`;
-CREATE TABLE `%TABLE_PREFIX%ticket_message` (
-  `msg_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `messageId` varchar(255) default NULL,
-  `message` text NOT NULL,
-  `headers` text,
-  `source` varchar(16) default NULL,
-  `ip_address` varchar(16) default NULL,
-  `created` datetime NOT NULL,
-  `updated` datetime default NULL,
-  PRIMARY KEY  (`msg_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `msgId` (`messageId`),
-  FULLTEXT KEY `message` (`message`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_note`;
-CREATE TABLE `%TABLE_PREFIX%ticket_note` (
-  `note_id` int(11) unsigned NOT NULL auto_increment,
-  `ticket_id` int(11) unsigned NOT NULL default '0',
-  `staff_id` int(10) unsigned NOT NULL default '0',
-  `source` varchar(32) NOT NULL default '',
-  `title` varchar(255) NOT NULL default 'Generic Intermal Notes',
-  `note` text NOT NULL,
-  `created` datetime NOT NULL,
-  PRIMARY KEY  (`note_id`),
-  KEY `ticket_id` (`ticket_id`),
-  KEY `staff_id` (`staff_id`),
-  FULLTEXT KEY `note` (`note`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
-
 DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`;
 CREATE TABLE `%TABLE_PREFIX%ticket_priority` (
   `priority_id` tinyint(4) NOT NULL auto_increment,
@@ -664,22 +640,24 @@ INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priorit
     (3, 'high', 'High', '#FEE7E7', 2, 1),
     (4, 'emergency', 'Emergency', '#FEE7E7', 1, 0);
 
-DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_response`;
-CREATE TABLE `%TABLE_PREFIX%ticket_response` (
-  `response_id` int(11) unsigned NOT NULL auto_increment,
-  `msg_id` int(11) unsigned NOT NULL default '0',
+DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`;
+CREATE TABLE `%TABLE_PREFIX%ticket_thread` (
+  `id` int(11) unsigned NOT NULL auto_increment,
+  `pid` int(11) unsigned NOT NULL default '0',
   `ticket_id` int(11) unsigned NOT NULL default '0',
   `staff_id` int(11) unsigned NOT NULL default '0',
-  `staff_name` varchar(32) NOT NULL default '',
-  `response` text NOT NULL,
-  `ip_address` varchar(16) NOT NULL default '',
+  `thread_type` enum('M','R','N') NOT NULL,
+  `poster` varchar(128) NOT NULL default '',
+  `source` varchar(32) NOT NULL default '',
+  `title` varchar(255),
+  `body` text NOT NULL,
+  `ip_address` varchar(64) NOT NULL default '',
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
-  PRIMARY KEY  (`response_id`),
+  PRIMARY KEY  (`id`),
   KEY `ticket_id` (`ticket_id`),
-  KEY `msg_id` (`msg_id`),
   KEY `staff_id` (`staff_id`),
-  FULLTEXT KEY `response` (`response`)
+  FULLTEXT KEY `body` (`body`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`;
diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 b/setup/inc/sql/osticket-v1.7-mysql.sql.md5
index 73090636d948f041c1a368ef416674c6269a309a..23011d006ad5e19d75630760bff1cfa872db12ec 100644
--- a/setup/inc/sql/osticket-v1.7-mysql.sql.md5
+++ b/setup/inc/sql/osticket-v1.7-mysql.sql.md5
@@ -1 +1 @@
-f8856d56e51c5cc3416389de78b54515
+abe9c0cb845be52c10fcd7b3e626a589