diff --git a/include/class.collaborator.php b/include/class.collaborator.php
index b123644a0d85b3276f2a8e3c9403adaaaa9b60f4..20e827c065a17d9d5a7207293b171c10b96dfc47 100644
--- a/include/class.collaborator.php
+++ b/include/class.collaborator.php
@@ -156,4 +156,19 @@ class Collaborator extends TicketUser {
             ? $c : null;
     }
 }
+
+class TicketCollaborator extends VerySimpleModel {
+    static $meta = array(
+        'table' => TICKET_COLLABORATOR_TABLE,
+        'pk' => array('id'),
+        'joins' => array(
+            'ticket' => array(
+                'constraint' => array('ticket_id' => 'TicketModel.ticket_id'),
+            ),
+            'user' => array(
+                'constraint' => array('user_id' => 'User.id'),
+            ),
+        ),
+    );
+}
 ?>
diff --git a/include/class.dept.php b/include/class.dept.php
index 4f8567d9256d8bc9e2db73bdf5d35b8cf6a6c567..bd77e48ec3ec973cfbc3d33211836006f00be127 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -364,7 +364,12 @@ class Dept extends VerySimpleModel {
 
     function getDefaultDeptName() {
         global $cfg;
-        return ($cfg && $cfg->getDefaultDeptId() && ($name=Dept::getNameById($cfg->getDefaultDeptId())))?$name:null;
+
+        return ($cfg
+            && ($did = $cfg->getDefaultDeptId())
+            && ($names = self::getDepartments()))
+            ? $names[$did]
+            : null;
     }
 
     static function getDepartments( $criteria=null) {
diff --git a/include/class.orm.php b/include/class.orm.php
index 58cf0a8f66067f9446dce449572d70bc8d3ef438..8338b84c7e65e739c9743a0112075de693a6fd47 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -1018,7 +1018,7 @@ class ModelInstanceManager extends ResultSet {
     }
 
     static function checkCache($modelClass, $fields) {
-        $key = $modelClass::$meta->model;
+        $key = $modelClass;
         foreach ($modelClass::$meta['pk'] as $f)
             $key .= '.'.$fields[$f];
         return @self::$objectCache[$key];
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 1e3c1eb64240842ab2d5867bc9fcf837ceeea220..0d3296f1f8a7cb2a7975b7270b3954cc376d3bb1 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -42,6 +42,10 @@ class TicketModel extends VerySimpleModel {
             'user' => array(
                 'constraint' => array('user_id' => 'User.id')
             ),
+            'collaborators' => array(
+                'reverse' => 'TicketCollaborator.ticket',
+                'null' => true,
+            ),
             'status' => array(
                 'constraint' => array('status_id' => 'TicketStatus.id')
             ),
diff --git a/include/class.user.php b/include/class.user.php
index aa016cd00ef53350f3d7d52480d208f55c62be4a..c8da82c12e6217340df74bbfd75ad5efbb6b3188 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -571,7 +571,7 @@ class User extends UserModel {
     }
 
     static function lookupByEmail($email) {
-        return self::lookup(array('emails__address'=>$email));
+        return static::lookup(array('emails__address'=>$email));
     }
 }
 
diff --git a/include/client/tickets.inc.php b/include/client/tickets.inc.php
index 8ebae5be121324e0a2221a51d66c0c65e6684b96..eb09a8559fcc39352bc794eeaf61ee7efd02bbe3 100644
--- a/include/client/tickets.inc.php
+++ b/include/client/tickets.inc.php
@@ -1,6 +1,8 @@
 <?php
 if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid()) die('Access Denied');
 
+$tickets = TicketModel::objects();
+
 $qstr='&'; //Query string collector
 $status=null;
 if(isset($_REQUEST['status'])) { //Query string status has nothing to do with the real status used below.
@@ -10,11 +12,11 @@ if(isset($_REQUEST['status'])) { //Query string status has nothing to do with th
     switch(strtolower($_REQUEST['status'])) {
      case 'open':
 		$results_type=__('Open Tickets');
+        $tickets->filter(array('status__state'=>'open'));
+        break;
      case 'closed':
 		$results_type=__('Closed Tickets');
-        break;
-     case 'resolved':
-        $results_type=__('Resolved Tickets');
+        $tickets->filter(array('status__state'=>'closed'));
         break;
      default:
         $status=''; //ignore
@@ -24,92 +26,66 @@ if(isset($_REQUEST['status'])) { //Query string status has nothing to do with th
 	$results_type=__('Open Tickets');
 }
 
-$sortOptions=array('id'=>'`number`', 'subject'=>'cdata.subject',
-                    'status'=>'status.name', 'dept'=>'dept.name','date'=>'ticket.created');
-$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
+$sortOptions=array('id'=>'number', 'subject'=>'cdata__subject',
+                    'status'=>'status__name', 'dept'=>'dept__name','date'=>'created');
+$orderWays=array('DESC'=>'-','ASC'=>'');
 //Sorting options...
 $order_by=$order=null;
 $sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date';
 if($sort && $sortOptions[$sort])
     $order_by =$sortOptions[$sort];
 
-$order_by=$order_by?$order_by:'ticket_created';
+$order_by=$order_by ?: $sortOptions['date'];
 if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
     $order=$orderWays[strtoupper($_REQUEST['order'])];
 
-$order=$order?$order:'ASC';
-if($order_by && strpos($order_by,','))
-    $order_by=str_replace(','," $order,",$order_by);
-
 $x=$sort.'_sort';
-$$x=' class="'.strtolower($order).'" ';
-
-$qselect='SELECT ticket.ticket_id,ticket.`number`,ticket.dept_id,isanswered, '
-    .'dept.ispublic, cdata.subject,'
-    .'dept.name as dept_name, status.name as status, status.state, ticket.source, ticket.created ';
+$$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" ';
 
-$qfrom='FROM '.TICKET_TABLE.' ticket '
-      .' LEFT JOIN '.TICKET_STATUS_TABLE.' status
-            ON (status.id = ticket.status_id) '
-      .' LEFT JOIN '.TABLE_PREFIX.'ticket__cdata cdata ON (cdata.ticket_id = ticket.ticket_id)'
-      .' LEFT JOIN '.DEPT_TABLE.' dept ON (ticket.dept_id=dept.dept_id) '
-      .' LEFT JOIN '.TICKET_COLLABORATOR_TABLE.' collab
-        ON (collab.ticket_id = ticket.ticket_id
-                AND collab.user_id ='.$thisclient->getId().' )';
-
-$qwhere = sprintf(' WHERE ( ticket.user_id=%d OR collab.user_id=%d )',
-            $thisclient->getId(), $thisclient->getId());
-
-$states = array(
-        'open' => 'open',
-        'closed' => 'closed');
-if($status && isset($states[$status])){
-    $qwhere.=' AND status.state='.db_input($states[$status]);
-}
+// Add visibility constraints
+$tickets->filter(Q::any(array(
+    'user_id' => $thisclient->getId(),
+    'collaborators__user_id' => $thisclient->getId(),
+)));
 
+// Perform basic search
 $search=($_REQUEST['a']=='search' && $_REQUEST['q']);
 if($search) {
     $qstr.='&a='.urlencode($_REQUEST['a']).'&q='.urlencode($_REQUEST['q']);
-    if(is_numeric($_REQUEST['q'])) {
-        $qwhere.=" AND ticket.`number` LIKE '$queryterm%'";
-    } else {//Deep search!
-        $queryterm=db_real_escape($_REQUEST['q'],false); //escape the term ONLY...no quotes.
-        $qwhere.=' AND ( '
-                ." cdata.subject LIKE '%$queryterm%'"
-                ." OR thread.body LIKE '%$queryterm%'"
-                .' ) ';
-        $deep_search=true;
-        //Joins needed for search
-        $qfrom.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ('
-               .'ticket.ticket_id=thread.ticket_id AND thread.thread_type IN ("M","R"))';
+    if (is_numeric($_REQUEST['q'])) {
+        $tickets->filter(array('number__startswith'=>$_REQUEST['q']));
+    } else { //Deep search!
+        // Use the search engine to perform the search
+        $tickets = $ost->searcher->find($_REQUEST['q'], $tickets);
     }
 }
 
 TicketForm::ensureDynamicDataView();
 
-$total=db_count('SELECT count(DISTINCT ticket.ticket_id) '.$qfrom.' '.$qwhere);
+$total=$tickets->count();
 $page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
 $pageNav=new Pagenate($total, $page, PAGE_LIMIT);
 $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']));
+$pageNav->paginate($tickets);
 
-//more stuff...
-$qselect.=' ,count(attach_id) as attachments ';
-$qfrom.=' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON  ticket.ticket_id=attach.ticket_id ';
-$qgroup=' GROUP BY ticket.ticket_id';
-
-$query="$qselect $qfrom $qwhere $qgroup ORDER BY $order_by $order LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
 //echo $query;
-$res = db_query($query);
-$showing=($res && db_num_rows($res))?$pageNav->showing():"";
+$showing =$total ? $pageNav->showing() : "";
 if(!$results_type)
 {
-	$results_type=ucfirst($status).' Tickets';
+	$results_type=ucfirst($status).' '.__('Tickets');
 }
 $showing.=($status)?(' '.$results_type):' '.__('All Tickets');
 if($search)
     $showing=__('Search Results').": $showing";
 
-$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting
+$negorder=$order=='-'?'ASC':'DESC'; //Negate the sorting
+
+$tickets->order_by($order.$order_by);
+$tickets->values(
+    'ticket_id', 'number', 'created', 'isanswered', 'source', 'status__id',
+    'status__state', 'status__name', 'cdata__subject', 'dept_id',
+    'dept__name', 'dept__ispublic', 'user__default_email__address'
+);
 
 ?>
 <h1><?php echo __('Tickets');?></h1>
@@ -158,31 +134,33 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting
     <tbody>
     <?php
      $subject_field = TicketForm::objects()->one()->getField('subject');
-     if($res && ($num=db_num_rows($res))) {
-        $defaultDept=Dept::getDefaultDeptName(); //Default public dept.
-        while ($row = db_fetch_array($res)) {
-            $dept= $row['ispublic']? $row['dept_name'] : $defaultDept;
+     $defaultDept=Dept::getDefaultDeptName(); //Default public dept.
+     if ($tickets->exists(true)) {
+         foreach ($tickets as $T) {
+            $dept = $T['dept__ispublic']
+                ? Dept::getLocalById($T['dept_id'], 'name', $T['dept__name'])
+                : $defaultDept;
             $subject = Format::truncate($subject_field->display(
-                $subject_field->to_php($row['subject']) ?: $row['subject']
+                $subject_field->to_php($T['cdata__subject']) ?: $T['cdata__subject']
             ), 40);
-            if($row['attachments'])
+            if (false) // XXX: Reimplement attachment count support
                 $subject.='  &nbsp;&nbsp;<span class="Icon file"></span>';
 
-            $ticketNumber=$row['number'];
-            if($row['isanswered'] && !strcasecmp($row['state'], 'open')) {
+            $ticketNumber=$T['number'];
+            if($T['isanswered'] && !strcasecmp($T['status__state'], 'open')) {
                 $subject="<b>$subject</b>";
                 $ticketNumber="<b>$ticketNumber</b>";
             }
             ?>
-            <tr id="<?php echo $row['ticket_id']; ?>">
+            <tr id="<?php echo $T['ticket_id']; ?>">
                 <td>
-                <a class="Icon <?php echo strtolower($row['source']); ?>Ticket" title="<?php echo $row['email']; ?>"
-                    href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $ticketNumber; ?></a>
+                <a class="Icon <?php echo strtolower($T['source']); ?>Ticket" title="<?php echo $T['user__default_email__address']; ?>"
+                    href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><?php echo $ticketNumber; ?></a>
                 </td>
-                <td>&nbsp;<?php echo Format::date($row['created']); ?></td>
-                <td>&nbsp;<?php echo $row['status']; ?></td>
+                <td>&nbsp;<?php echo Format::date($T['created']); ?></td>
+                <td>&nbsp;<?php echo $T['status__name']; ?></td>
                 <td>
-                    <a href="tickets.php?id=<?php echo $row['ticket_id']; ?>"><?php echo $subject; ?></a>
+                    <a href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><?php echo $subject; ?></a>
                 </td>
                 <td>&nbsp;<?php echo Format::truncate($dept,30); ?></td>
             </tr>
@@ -196,7 +174,7 @@ $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting
     </tbody>
 </table>
 <?php
-if($res && $num>0) {
+if ($total) {
     echo '<div>&nbsp;'.__('Page').':'.$pageNav->getPageLinks().'&nbsp;</div>';
 }
 ?>