diff --git a/include/class.thread.php b/include/class.thread.php
new file mode 100644
index 0000000000000000000000000000000000000000..f830cd98ead00f6a553d8a0d5b77126b2ccfa80e
--- /dev/null
+++ b/include/class.thread.php
@@ -0,0 +1,222 @@
+<?php
+/*********************************************************************
+    class.thread.php
+
+    Ticket thread
+    TODO: move thread related logic here from class.ticket.php
+
+    Peter Rotich <peter@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+include_once(INCLUDE_DIR.'class.ticket.php');
+
+Class ThreadEntry {
+
+    var $id;
+    var $ht;
+
+    var $staff;
+    var $ticket;
+    
+    function ThreadEntry($id, $type='', $ticketId=0) {
+        $this->load($id, $type, $ticketId);
+    }
+
+    function load($id=0, $type='', $ticketId=0) {
+
+        if(!$id && !($id=$this->getId()))
+            return false;
+
+        $sql='SELECT thread.* '
+            .' ,count(DISTINCT attach.attach_id) as attachments '
+            .' FROM '.TICKET_THREAD_TABLE.' thread '
+            .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach 
+                ON (thread.ticket_id=attach.ticket_id 
+                        AND thread.id=attach.ref_id 
+                        AND thread.thread_type=attach.ref_type) '
+            .' WHERE  thread.id='.db_input($id);
+
+        if($type)
+            $sql.=' AND thread.thread_type='.db_input($type);
+
+        if($ticketId)
+            $sql.=' AND thread.ticket_id='.db_input($ticketId);
+
+        $sql.=' GROUP BY thread.id ';
+        
+        if(!($res=db_query($sql)) || !db_num_rows($res))
+            return false;
+
+        $this->ht = db_fetch_array($res);
+        $this->id = $this->ht['id'];
+
+        $this->staff = $this->ticket = null;
+
+        return true;
+    }
+
+    function reload() {
+        return $this->load();
+    }
+
+    function getId() {
+        return $this->id;
+    }
+
+    function getPid() {
+        return $this->ht['pid'];
+    }
+
+    function getType() {
+        return $this->ht['thread_type'];
+    }
+
+    function getSource() {
+        return $this->ht['source'];
+    }
+
+    function getPoster() {
+        return $this->ht['poster'];
+    }
+
+    function getTitle() {
+        return $this->ht['title'];
+    }
+
+    function getBody() {
+        return $this->ht['body'];
+    }
+
+    function getCreateDate() {
+        return $this->ht['created'];
+    }
+
+    function getUpdateDate() {
+        return $this->ht['updated'];
+    }
+
+    function getNumAttachments() {
+        return $this->ht['attachments'];
+    }
+
+    function getTicketId() {
+        return $this->ht['ticket_id'];
+    }
+
+    function getTicket() {
+
+        if(!$this->ticket && $this->getTicketId())
+            $this->ticket = Ticket::lookup($this->getTicketId());
+
+        return $this->ticket;
+    }
+
+    function getStaffId() {
+        return $this->ht['staff_id'];
+    }
+
+    function getStaff() {
+      
+        if(!$this->staff && $this->getStaffId())
+            $this->staff = Staff::lookup($this->getStaffId());
+
+        return $this->staff;
+    }
+
+    /* variables */
+
+    function asVar() {
+        return $this->getBody();
+    }
+
+    function getVar($tag) {
+        global $cfg;
+
+        if($tag && is_callable(array($this, 'get'.ucfirst($tag))))
+            return call_user_func(array($this, 'get'.ucfirst($tag)));
+
+        switch(strtolower($tag)) {
+            case 'create_date':
+                return Format::date(
+                        $cfg->getDateTimeFormat(),
+                        Misc::db2gmtime($this->getCreateDate()),
+                        $cfg->getTZOffset(),
+                        $cfg->observeDaylightSaving());
+                break;
+            case 'update_date':
+                return Format::date(
+                        $cfg->getDateTimeFormat(),
+                        Misc::db2gmtime($this->getUpdateDate()),
+                        $cfg->getTZOffset(),
+                        $cfg->observeDaylightSaving());
+                break;
+        }
+
+        return false;
+    }
+
+    /* static calls */
+
+    function _lookup($id, $type='', $tid=0) {
+        return ($id && is_numeric($id) 
+                && ($e = new ThreadEntry($id, $type, $tid)) && $e->getId()==$id)?$e:null;
+    }
+}
+
+/* Message - Ticket thread entry of type message */
+class Message extends ThreadEntry {
+
+    function Message($id, $ticketId=0) {
+        parent::ThreadEntry($id, 'M', $ticketId);
+    }
+
+    function getSubject() {
+        return $this->getTitle();
+    }
+
+    function lookup($id, $tid) {
+        return parent::_lookup($id, 'M', $tid);
+    }
+}
+
+/* Response - Ticket thread entry of type response */
+class Response extends ThreadEntry {
+
+    function Response($id, $ticketId=0) {
+        parent::ThreadEntry($id, 'R', $ticketId);
+    }
+
+    function getSubject() {
+        return $this->getTitle();
+    }
+
+    function getRespondent() {
+        return $this->getStaff();
+    }
+
+    function lookup($id, $tid) {
+        return parent::_lookup($id, 'R', $tid);
+    }
+}
+
+/* Note - Ticket thread entry of type note (Internal Note) */
+class Note extends ThreadEntry {
+
+    function Note($id, $ticketId=0) {
+        parent::ThreadEntry($id, 'N', $ticketId);
+    }
+
+    function getMessage() {
+        return $this->getBody();
+    }
+
+    function lookup($id, $tid) {
+        return parent::_lookup($id, 'N', $tid);
+    }
+}