I am using osticket and I want to add some features on it... for example I want to add live tickets feature (each time a new ticket is created from the client side a notification should appear on the staff page and the ticket should dynamically appear...
Here are some files (not all of them, if you want more files tell me):

/include/ajax.tickets.php:
<?php
/*********************************************************************
    ajax.tickets.php

    AJAX interface for tickets

    Peter Rotich <peter@osticket.com>
    Copyright (c)  2006-2013 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:
**********************************************************************/

if(!defined('INCLUDE_DIR')) die('403');

include_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.ajax.php');
require_once(INCLUDE_DIR.'class.note.php');
include_once INCLUDE_DIR . 'class.thread_actions.php';

class TicketsAjaxAPI extends AjaxController {

    function lookup() {
        global $thisstaff;

        $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
        $tickets=array();
        // Bail out of query is empty
        if (!$_REQUEST['q'])
            return $this->json_encode($tickets);

        $visibility = $thisstaff->getTicketsVisibility();
        $hits = Ticket::objects()
            ->filter($visibility)
            ->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags')
            ->annotate(array(
                'number' => new SqlCode('null'),
                'tickets' => SqlAggregate::COUNT('ticket_id', true),
                'tasks' => SqlAggregate::COUNT('tasks__id', true),
                'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
                'entries' => SqlAggregate::COUNT('thread__entries__id', true),
            ))
            ->order_by(SqlAggregate::SUM(new SqlCode('Z1.relevance')), QuerySet::DESC)
            ->distinct('user__default_email__address')
            ->limit($limit);

        $q = $_REQUEST['q'];

        if (strlen(Format::searchable($q)) < 3)
            return $this->encode(array());

        global $ost;
        $hits = $ost->searcher->find($q, $hits, false);

        $T = array();
        if (preg_match('/\d{2,}[^*]/', $q, $T)) {
            $hits = $this->lookupByNumber($limit, $visibility, $hits);
        }
        elseif (preg_match('/(.*@.{2,})|(.{2,}@.*)/', $q, $T)) {
            $hits = $this->lookupByEmail($limit, $visibility, $hits);
        }
        elseif (!count($hits) && preg_match('`\w$`u', $q)) {
            // Do wild-card fulltext search
            $_REQUEST['q'] = $q.'*';
            return $this->lookup();
        }

        // TODO: Why not aggregate based on relationship?
        foreach ($hits as $T) {
            $email = $T['user__default_email__address'];
            $count = $T['tickets'];
            if ($T['number']) {
                $tickets[$T['number']] = array('id'=>$T['number'], 'value'=>$T['number'],
                    'ticket_id'=>$T['ticket_id'],
                    'info'=>"{$T['number']} — {$email}",
                    'subject'=>$T['cdata__subject'],
                    'user'=>$T['user__name'],
                    'tasks'=>$T['tasks'],
                    'thread_id'=>$T['thread__id'],
                    'collaborators'=>$T['collaborators'],
                    'entries'=>$T['entries'],
                    'mergeType'=>Ticket::getMergeTypeByFlag($T['flags']),
                    'children'=>count(Ticket::getChildTickets($T['ticket_id'])) > 0 ? true : false,
                    'matches'=>$_REQUEST['q']);
            }
            else {
                $tickets[$email] = array('email'=>$email, 'value'=>$email,
                    'info'=>"$email ($count)", 'matches'=>$_REQUEST['q']);
            }
        }
        $tickets = array_values($tickets);

        return $this->json_encode($tickets);
    }

    function lookupByNumber($limit=false, $visibility=false, $matches=false) {
        global $thisstaff;

        if (!$limit)
            $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;

        $tickets=array();
        // Bail out of query is empty
        if (!$_REQUEST['q'])
            return $this->json_encode($tickets);

        $q = trim($_REQUEST['q']);

        if (!$visibility)
            $visibility = $thisstaff->getTicketsVisibility();

        $hits = Ticket::objects()
            ->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags', 'number')
            ->annotate(array(
                'tickets' => new SqlCode('1'),
                'tasks' => SqlAggregate::COUNT('tasks__id', true),
                'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
                'entries' => SqlAggregate::COUNT('thread__entries__id', true),
            ))
            ->filter($visibility)
            ->filter(array('number__startswith' => $q))
            ->order_by('number')
            ->limit($limit);

        if ($matches && is_a($matches, 'QuerySet'))
            return $hits->union($matches);

        foreach ($hits as $T) {
            $email = $T['user__default_email__address'];
            $tickets[$T['number']] = array('id'=>$T['number'], 'value'=>$T['number'],
                'ticket_id'=>$T['ticket_id'],
                'info'=>"{$T['number']} — {$email}",
                'subject'=>$T['cdata__subject'],
                'user'=>$T['user__name'],
                'tasks'=>$T['tasks'],
                'thread_id'=>$T['thread__id'],
                'collaborators'=>$T['collaborators'],
                'entries'=>$T['entries'],
                'mergeType'=>Ticket::getMergeTypeByFlag($T['flags']),
                'children'=>count(Ticket::getChildTickets($T['ticket_id'])) > 0 ? true : false,
                'matches'=>$_REQUEST['q']);
        }
        $tickets = array_values($tickets);

        return $this->json_encode($tickets);
    }

    function lookupByEmail($limit=false, $visibility=false, $matches=false) {
        global $thisstaff;

        if (!$limit)
            $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;

        $tickets=array();
        // Bail out of query is empty
        if (!$_REQUEST['q'])
            return $this->json_encode($tickets);

        $q = trim($_REQUEST['q']);

        if (!$visibility)
            $visibility = $thisstaff->getTicketsVisibility();

        $hits = Ticket::objects()
            ->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags')
            ->annotate(array(
                'number' => new SqlCode('null'),
                'tickets' => SqlAggregate::COUNT('ticket_id', true),
                'tasks' => SqlAggregate::COUNT('tasks__id', true),
                'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
                'entries' => SqlAggregate::COUNT('thread__entries__id', true),
            ))
            ->filter($visibility)
            ->filter(array('user__default_email__address__contains' => $q))
            ->order_by('user__default_email__address')
            ->limit($limit);

        if ($matches && is_a($matches, 'QuerySet'))
            return $hits->union($matches);

        foreach ($hits as $T) {
            $count = $T['tickets'];
            $email = $T['user__default_email__address'];
            $tickets[$email] = array('email'=>$email, 'value'=>$email,
                'info'=>"$email ($count)", 'matches'=>$_REQUEST['q']);
        }
        $tickets = array_values($tickets);

        return $this->json_encode($tickets);
    }

    function acquireLock($tid) {
        global $cfg, $thisstaff;

        if(!$cfg || !$cfg->getLockTime() || $cfg->getTicketLockMode() == Lock::MODE_DISABLED)
            Http::response(418, $this->encode(array('id'=>0, 'retry'=>false)));

        if(!$tid || !is_numeric($tid) || !$thisstaff)
            return 0;

        if (!($ticket = Ticket::lookup($tid)) || !$ticket->checkStaffPerm($thisstaff))
            return $this->encode(array('id'=>0, 'retry'=>false, 'msg'=>__('Lock denied!')));

        //is the ticket already locked?
        if ($ticket->isLocked() && ($lock=$ticket->getLock()) && !$lock->isExpired()) {
            /*Note: Ticket->acquireLock does the same logic...but we need it here since we need to know who owns the lock up front*/
            //Ticket is locked by someone else.??
            if ($lock->getStaffId() != $thisstaff->getId())
                return $this->json_encode(array('id'=>0, 'retry'=>false,
                    'msg' => sprintf(__('Currently locked by %s'),
                        $lock->getStaff()->getAvatarAndName())
                    ));

            //Ticket already locked by staff...try renewing it.
            $lock->renew(); //New clock baby!
        } elseif(!($lock=$ticket->acquireLock($thisstaff->getId(),$cfg->getLockTime()))) {
            //unable to obtain the lock..for some really weired reason!
            //Client should watch for possible loop on retries. Max attempts?
            return $this->json_encode(array('id'=>0, 'retry'=>true));
        }

        return $this->json_encode(array(
            'id'=>$lock->getId(), 'time'=>$lock->getTime(),
            'code' => $lock->getCode()
        ));
    }

    function renewLock($id, $ticketId) {
        global $thisstaff;

        if (!$id || !is_numeric($id) || !$thisstaff)
            Http::response(403, $this->encode(array('id'=>0, 'retry'=>false)));
        if (!($lock = Lock::lookup($id)))
            Http::response(404, $this->encode(array('id'=>0, 'retry'=>'acquire')));
        if (!($ticket = Ticket::lookup($ticketId)) || $ticket->lock_id != $lock->lock_id)
            // Ticket / Lock mismatch
            Http::response(400, $this->encode(array('id'=>0, 'retry'=>false)));

        if (!$lock->getStaffId() || $lock->isExpired())
            // Said lock doesn't exist or is is expired — fetch a new lock
            return self::acquireLock($ticket->getId());

        if ($lock->getStaffId() != $thisstaff->getId())
            // user doesn't own the lock anymore??? sorry...try to next time.
            Http::response(403, $this->encode(array('id'=>0, 'retry'=>false,
                'msg' => sprintf(__('Currently locked by %s'),
                    $lock->getStaff->getAvatarAndName())
            ))); //Give up...

        // Ensure staff still has access
        if (!$ticket->checkStaffPerm($thisstaff))
            Http::response(403, $this->encode(array('id'=>0, 'retry'=>false,
                'msg' => sprintf(__('You no longer have access to #%s.'),
                $ticket->getNumber())
            )));

        // Renew the lock.
        // Failure here is not an issue since the lock is not expired yet.. client need to check time!
        $lock->renew();

        return $this->encode(array('id'=>$lock->getId(), 'time'=>$lock->getTime(),
            'code' => $lock->getCode()));
    }

    function releaseLock($id) {
        global $thisstaff;

        if (!$id || !is_numeric($id) || !$thisstaff)
            Http::response(403, $this->encode(array('id'=>0, 'retry'=>true)));
        if (!($lock = Lock::lookup($id)))
            Http::response(404, $this->encode(array('id'=>0, 'retry'=>true)));

        // You have to own the lock
        if ($lock->getStaffId() != $thisstaff->getId()) {
            return 0;
        }
        // Can't be expired
        if ($lock->isExpired()) {
            return 1;
        }
        return $lock->release() ? 1 : 0;
    }

    function previewTicket ($tid) {
        global $thisstaff;

        if(!$thisstaff || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, __('No such ticket'));

        include STAFFINC_DIR . 'templates/ticket-preview.tmpl.php';
    }

    function viewUser($tid) {
        global $thisstaff;

        if(!$thisstaff
                || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'No such ticket');


        if(!($user = User::lookup($ticket->getOwnerId())))
            Http::response(404, 'Unknown user');


        $info = array(
            'title' => sprintf(__('Ticket #%s: %s'), $ticket->getNumber(),
                Format::htmlchars($user->getName()))
            );

        ob_start();
        include(STAFFINC_DIR . 'templates/user.tmpl.php');
        $resp = ob_get_contents();
        ob_end_clean();
        return $resp;

    }

    function updateUser($tid) {

        global $thisstaff;

        if(!$thisstaff
                || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff)
                || !($user = User::lookup($ticket->getOwnerId())))
            Http::response(404, 'No such ticket/user');

        $errors = array();
        if($user->updateInfo($_POST, $errors, true))
             Http::response(201, $user->to_json());

        $forms = $user->getForms();

        $info = array(
            'title' => sprintf(__('Ticket #%s: %s'), $ticket->getNumber(),
                Format::htmlchars($user->getName()))
            );

        ob_start();
        include(STAFFINC_DIR . 'templates/user.tmpl.php');
        $resp = ob_get_contents();
        ob_end_clean();
        return $resp;
    }

    function changeUserForm($tid) {
        global $thisstaff;

        if(!$thisstaff
                || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'No such ticket');


        $user = User::lookup($ticket->getOwnerId());

        $info = array(
                'title' => sprintf(__('Change user for ticket #%s'), $ticket->getNumber())
                );

        return self::_userlookup($user, null, $info);
    }

    static function _userlookup($user, $form, $info) {
        global $thisstaff;

        ob_start();
        include(STAFFINC_DIR . 'templates/user-lookup.tmpl.php');
        $resp = ob_get_contents();
        ob_end_clean();
        return $resp;

    }

    function manageForms($ticket_id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required");
        elseif (!($ticket = Ticket::lookup($ticket_id)))
            Http::response(404, "No such ticket");
        elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
            Http::response(403, "Access Denied");

        $forms = DynamicFormEntry::forTicket($ticket->getId());
        $info = array('action' => '#tickets/'.$ticket->getId().'/forms/manage');
        include(STAFFINC_DIR . 'templates/form-manage.tmpl.php');
    }

    function updateForms($ticket_id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required");
        elseif (!($ticket = Ticket::lookup($ticket_id)))
            Http::response(404, "No such ticket");
        elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
            Http::response(403, "Access Denied");
        elseif (!isset($_POST['forms']))
            Http::response(422, "Send updated forms list");

        // Add new forms
        $forms = DynamicFormEntry::forTicket($ticket_id);
        foreach ($_POST['forms'] as $sort => $id) {
            $found = false;
            foreach ($forms as $e) {
                if ($e->get('form_id') == $id) {
                    $e->set('sort', $sort);
                    $e->save();
                    $found = true;
                    break;
                }
            }
            // New form added
            if (!$found && ($new = DynamicForm::lookup($id))) {
                $f = $new->instanciate();
                $f->set('sort', $sort);
                $f->setTicketId($ticket_id);
                $f->save();
            }
        }

        // Deleted forms
        foreach ($forms as $idx => $e) {
            if (!in_array($e->get('form_id'), $_POST['forms']))
                $e->delete();
        }

        Http::response(201, 'Successfully managed');
    }

    function mergeTickets($ticket_id) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, "Login required");
        elseif (!($ticket = Ticket::lookup($ticket_id)))
            Http::response(404, "No such ticket");
        elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
            Http::response(403, "Access Denied");

        //retrieve the parent and child tickets
        $parent = Ticket::objects()
            ->filter(array('ticket_id'=>$ticket_id))
            ->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id', 'user_id', 'cdata__subject', 'user__name', 'flags')
            ->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
                             'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
                             'entries' => SqlAggregate::COUNT('thread__entries__id', true),));
        $tickets =  Ticket::getChildTickets($ticket_id);
        $tickets = $parent->union($tickets);

        //fix sort of tickets
        $sql = sprintf('SELECT * FROM (%s) a ORDER BY sort', $tickets->getQuery());
        $res = db_query($sql);
        $tickets = db_assoc_array($res);
        $info = array('action' => '#tickets/'.$ticket->getId().'/merge');

        return self::_updateMerge($ticket, $tickets, $info);
    }

    function updateMerge($ticket_id) {
        global $thisstaff;

        $info = array();
        $errors = array();

        if ($_POST['dtids']) {
            foreach($_POST['dtids'] as $key => $value) {
                if (is_numeric($key) && $ticket = Ticket::lookup($value))
                    $ticket->unlink();
            }
            Http::response(201, 'Successfully managed');
        } elseif ($_POST['tids']) {
            if ($parent = Ticket::merge($_POST))
                Http::response(201, 'Successfully managed');
            else
                Http::response(404, 'Unable to manage ticket');
        }

        $parentModel = Ticket::objects()
            ->filter(array('ticket_id'=>$ticket_id))
            ->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id', 'user_id', 'cdata__subject', 'user__name', 'flags')
            ->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
                             'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
                             'entries' => SqlAggregate::COUNT('thread__entries__id', true),));

        if ($parent->getMergeType() == 'visual') {
            $tickets = Ticket::getChildTickets($ticket_id);
            $tickets = $parentModel->union($tickets);
        } else
            $tickets = $parentModel;

        return self::_updateMerge($parent, $tickets, $info);
    }

    static private function _updateMerge($ticket, $tickets, $info) {
        include(STAFFINC_DIR . 'templates/merge-tickets.tmpl.php');
    }

    function previewMerge($tid) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'No such ticket');

        ob_start();
        include STAFFINC_DIR . 'templates/merge-preview.tmpl.php';
        $resp = ob_get_contents();
        ob_end_clean();

        return $resp;
    }

    function cannedResponse($tid, $cid, $format='text') {
        global $thisstaff, $cfg;

        if (!($ticket = Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket ID');


        if ($cid && !is_numeric($cid)) {
            if (!($response=$ticket->getThread()->getVar($cid)))
                Http::response(422, 'Unknown ticket variable');

            // Ticket thread variables are assumed to be quotes
            $response = "<br/><blockquote>{$response->asVar()}</blockquote><br/>";

            //  Return text if html thread is not enabled
            if (!$cfg->isRichTextEnabled())
                $response = Format::html2text($response, 90);
            else
                $response = Format::viewableImages($response);

            // XXX: assuming json format for now.
            return Format::json_encode(array('response' => $response));
        }

        if (!$cfg->isRichTextEnabled())
            $format.='.plain';

        $varReplacer = function (&$var) use($ticket) {
            return $ticket->replaceVars($var, array('recipient' => $ticket->getOwner()));
        };

        include_once(INCLUDE_DIR.'class.canned.php');
        if (!$cid || !($canned=Canned::lookup($cid)) || !$canned->isEnabled())
            Http::response(404, 'No such premade reply');

        return $canned->getFormattedResponse($format, $varReplacer);
    }

    function transfer($tid) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_TRANSFER))
            Http::response(403, __('Permission denied'));

        $errors = array();

        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s'),
                    $ticket->getNumber(),
                    __('Transfer')),
                ':action' => sprintf('#tickets/%d/transfer',
                    $ticket->getId())
                );

        $form = $ticket->getTransferForm($_POST);
        if ($_POST && $form->isValid()) {
            if ($ticket->transfer($form, $errors)) {
                $_SESSION['::sysmsgs']['msg'] = sprintf(
                        __('%s successfully'),
                        sprintf(
                            __('%s transferred to %s department'),
                            __('Ticket'),
                            $ticket->getDept()
                            )
                        );
                Http::response(201, $ticket->getId());
            }
            $form->addErrors($errors);
            $info['error'] = $errors['err'] ?: __('Unable to transfer ticket');
        }

        $info['dept_id'] = $info['dept_id'] ?: $ticket->getDeptId();

        include STAFFINC_DIR . 'templates/transfer.tmpl.php';
    }

    function referrals($tid) {
      return $this->refer($tid);
    }

    function refer($tid, $target=null) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
                || !($form = $ticket->getReferralForm($_POST,
                        array('target' => $target))))
            Http::response(403, __('Permission denied'));

        $errors = array();
        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s'),
                    $ticket->getNumber(),
                    __('Refer')
                    ),
                ':action' => sprintf('#tickets/%d/refer%s',
                    $ticket->getId(),
                    ($target  ? "/$target": '')),
                );

        if ($_POST) {
            switch ($_POST['do']) {
                case 'refer':
                    if ($form->isValid() && $ticket->refer($form, $errors)) {
                        $clean = $form->getClean();
                        if ($clean['comments'])
                            $ticket->logNote('Referral', $clean['comments'], $thisstaff);
                        $_SESSION['::sysmsgs']['msg'] = sprintf(
                                __('%s successfully'),
                                sprintf(
                                    __('%s referred to %s'),
                                    sprintf(__('Ticket #%s'),
                                         sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
                                             $ticket->getId(),
                                             $ticket->getNumber()))
                                    ,
                                    $form->getReferee())
                                );
                        Http::response(201, $ticket->getId());
                    }

                    $form->addErrors($errors);
                    $info['error'] = $errors['err'] ?: __('Unable to refer ticket');
                    break;
                case 'manage':
                    $remove = array();
                    if (is_array($_POST['referrals'])) {
                        $remove = array();
                        foreach ($_POST['referrals'] as $k => $v)
                            if ($v[0] == '-')
                                $remove[] = substr($v, 1);
                        if (count($remove)) {
                            $num = $ticket->getThread()->referrals
                                ->filter(array('id__in' => $remove))
                                ->delete();
                            if ($num) {
                                $info['msg'] = sprintf(
                                        __('%s successfully'),
                                        sprintf(__('Removed %d referrals'),
                                            $num
                                            )
                                        );
                            }
                            //TODO: log removal
                        }
                    }
                    break;
                default:
                     $errors['err'] = __('Unknown Action');
            }
        }

        $thread = $ticket->getThread();
        include STAFFINC_DIR . 'templates/refer.tmpl.php';
    }

    function editField($tid, $fid) {
        global $cfg, $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));
        elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
            Http::response(403, __('Permission denied'));
        elseif (!($field=$ticket->getField($fid)))
            Http::response(404, __('No such field'));

        $errors = array();
        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s %s'),
                  $ticket->getNumber(),
                  __('Update'),
                  $field->getLabel()
                  ),
              ':action' => sprintf('#tickets/%d/field/%s/edit',
                  $ticket->getId(), $field->getId())
              );

        $form = $field->getEditForm($_POST);
        if ($_POST && $form->isValid()) {

            if ($ticket->updateField($form, $errors)) {
                $msg = sprintf(
                      __('%s successfully'),
                      sprintf(
                          __('%s updated'),
                          __($field->getLabel())
                          )
                      );

                switch (true) {
                    case $field instanceof DateTime:
                    case $field instanceof DatetimeField:
                        $clean = Format::datetime((string) $field->getClean());
                        break;
                    case $field instanceof FileUploadField:
                        $field->save();
                        $answer =  $field->getAnswer();
                        $clean = $answer->display() ?: '&mdash;' . __('Empty') .  '&mdash;';
                        break;
                    case $field instanceof DepartmentField:
                        $clean = (string) Dept::lookup($field->getClean());
                        break;
                    case $field instanceof TextareaField:
                        $clean =  (string) $field->getClean();
                        $clean = Format::striptags($clean) ?: '&mdash;' . __('Empty') .  '&mdash;';
                        if (strlen($clean) > 200)
                             $clean = Format::truncate(Format::striptags($clean), 200);
                        break;
                    case $field instanceof BooleanField:
                        $clean = $field->toString($field->getClean());
                        break;
                    default:
                        $clean =  $field->getClean();
                        $clean = is_array($clean) ? implode(',', $clean) :
                            (string) $clean;
                }

                // Set basic response data
                $response = array(
                    'value' => $clean ?: '&mdash;' . __('Empty') .  '&mdash;',
                    'id' => $fid, 'msg' => $msg
                );

                // If we require HT to close, the ticket is open, the staff has permission
                // to close, and we set a HT - ensure we provide all available statuses
                if ($cfg->requireTopicToClose() && $ticket->isOpen()
                        && $ticket->checkStaffPerm($thisstaff, Ticket::PERM_CLOSE)
                        && ($field instanceof TopicField) && $clean) {
                    $statuses = array();
                    foreach (TicketStatusList::getStatuses(
                            array('states' => array('closed'))) as $s) {
                        if (!$s->isEnabled()) continue;
                        $statuses[$s->getId()] = $s->getName();
                    }
                    if (!is_null($statuses))
                        $response['statuses'] = $statuses;
                }

                $clean = is_array($clean) ? $clean[0] : $clean;
                Http::response(201, $this->json_encode($response));
            }

            $form->addErrors($errors);
            $info['error'] = $errors['err'] ?: __('Unable to update field');
        }

        include STAFFINC_DIR . 'templates/field-edit.tmpl.php';
    }

    function viewField($tid, $fid) {
        global $cfg, $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));
        elseif (!($field=$ticket->getField($fid)))
            Http::response(404, __('No such field'));

        $errors = array();
        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s %s'),
                  $ticket->getNumber(),
                  __('View'),
                  $field->getLabel()
                  ),
              ':action' => sprintf('#tickets/%d/field/%s/edit',
                  $ticket->getId(), $field->getId())
              );

        $form = $field->getEditForm();

        include STAFFINC_DIR . 'templates/field-view.tmpl.php';
    }

    function assign($tid, $target=null) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
                || !($form = $ticket->getAssignmentForm($_POST,
                        array('target' => $target))))
            Http::response(403, __('Permission denied'));

        $errors = array();
        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s'),
                    $ticket->getNumber(),
                    sprintf('%s %s',
                        $ticket->isAssigned() ?
                            __('Reassign') :  __('Assign'),
                        !strcasecmp($target, 'agents') ?
                            __('to an Agent') : __('to a Team')
                    )),
                ':action' => sprintf('#tickets/%d/assign%s',
                    $ticket->getId(),
                    ($target  ? "/$target": '')),
                );

        if ($ticket->isAssigned()) {
            if ($ticket->getStaffId() == $thisstaff->getId())
                $assigned = __('you');
            else
                $assigned = $ticket->getAssigned();

            $info['notice'] = sprintf(__('%s is currently assigned to <b>%s</b>'),
                    __('This ticket'),
                    Format::htmlchars($assigned)
                    );
        }

        if ($_POST && $form->isValid()) {
            if ($ticket->assign($form, $errors)) {
                $msg = sprintf(
                        __('%s successfully'),
                        sprintf(
                            __('%s assigned to %s'),
                            __('Ticket'),
                            $form->getAssignee())
                        );

                $assignee =  $ticket->isAssigned() ? Format::htmlchars(implode('/', $ticket->getAssignees())) :
                                            '<span class="faded">&mdash; '.__('Unassigned').' &mdash;';
                Http::response(201, $this->json_encode(['value' =>
                    $assignee, 'id' => 'assign', 'msg' => $msg]));
            }

            $form->addErrors($errors);
            $info['error'] = $errors['err'] ?: __('Unable to assign ticket');
        }

        include STAFFINC_DIR . 'templates/assign.tmpl.php';
    }

    function claim($tid) {

        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        // Check for premissions and such
        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
                || !$ticket->isOpen() // Claim only open
                || $ticket->getStaff() // cannot claim assigned ticket
                || !($form = $ticket->getClaimForm($_POST)))
            Http::response(403, __('Permission denied'));

        $errors = array();
        $info = array(
                ':title' => sprintf(__('Ticket #%s: %s'),
                    $ticket->getNumber(),
                    __('Claim')),
                ':action' => sprintf('#tickets/%d/claim',
                    $ticket->getId()),

                );

        if ($ticket->isAssigned()) {
            if ($ticket->getStaffId() == $thisstaff->getId())
                $assigned = __('you');
            else
                $assigned = $ticket->getAssigned();

            $info['error'] = sprintf(__('%s is currently assigned to <b>%s</b>'),
                    __('This ticket'),
                    $assigned);
        } else {
            $info['warn'] = sprintf(__('Are you sure you want to CLAIM %s?'),
                    __('this ticket'));
        }

        if ($_POST && $form->isValid()) {
            if ($ticket->claim($form, $errors)) {
                $_SESSION['::sysmsgs']['msg'] = sprintf(
                        __('%s successfully'),
                        sprintf(
                            __('%s assigned to %s'),
                            __('Ticket'),
                            __('you'))
                        );
                Http::response(201, $ticket->getId());
            }

            $form->addErrors($errors);
            $info['error'] = $errors['err'] ?: __('Unable to claim ticket');
        }

        $verb = sprintf('%s, %s', __('Yes'), __('Claim'));

        include STAFFINC_DIR . 'templates/assign.tmpl.php';

    }

    function release($tid) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_RELEASE) && !$thisstaff->isManager())
            Http::response(403, __('Permission denied'));

        $errors = array();
        if (!$ticket->isAssigned())
            $errors['err'] = __('Ticket is not assigned!');

        $info = array(':title' => sprintf(__('Ticket #%s: %s'),
                    $ticket->getNumber(),
                    __('Release Confirmation')));

        $form = ReleaseForm::instantiate($_POST);
        $hasData = ($_POST['sid'] || $_POST['tid']);

        $staff = $ticket->getStaff();
        $team = $ticket->getTeam();
        if ($_POST) {
            if ($hasData && $ticket->release($_POST, $errors)) {
                $data = array();

                if ($staff && !$ticket->getStaff())
                    $data['staff'] = array($staff->getId(), (string) $staff->getName()->getOriginal());
                if ($team && !$ticket->getTeam())
                    $data['team'] = $team->getId();
                $ticket->logEvent('released', $data);

                $comments = $form->getComments();
                if ($comments) {
                    $title = __('Assignment Released');
                    $_errors = array();

                    $ticket->postNote(
                        array('note' => $comments, 'title' => $title),
                        $_errors, $thisstaff, false);
                }

                $_SESSION['::sysmsgs']['msg'] = __('Ticket assignment released successfully');
                Http::response(201, $ticket->getId());
            }

            if (!$hasData)
                $errors['err'] = __('Please check an assignee to release assignment');

            $form->addErrors($errors);
            $info['error'] = $errors['err'] ?: __('Unable to release ticket assignment');
        }

        if($errors && $errors['err'])
            $info['error'] = $errors['err'] ?: __('Unable to release ticket');

        include STAFFINC_DIR . 'templates/release.tmpl.php';
    }

    function massProcess($action, $w=null)  {
        global $thisstaff, $cfg;

        $actions = array(
                'transfer' => array(
                    'verbed' => __('transferred'),
                    ),
                'assign' => array(
                    'verbed' => __('assigned'),
                    ),
                'refer' => array(
                    'verbed' => __('referred'),
                    ),
                'merge' => array(
                    'verbed' => __('merged'),
                    ),
                'link' => array(
                    'verbed' => __('linked'),
                    ),
                'claim' => array(
                    'verbed' => __('assigned'),
                    ),
                'delete' => array(
                    'verbed' => __('deleted'),
                    ),
                'reopen' => array(
                    'verbed' => __('reopen'),
                    ),
                'close' => array(
                    'verbed' => __('closed'),
                    ),
                );

        if (!isset($actions[$action]))
            Http::response(404, __('Unknown action'));


        $info = $errors = $e = array();
        $inc = null;
        $i = $count = 0;
        if ($_POST) {
            if (!$_POST['tids'] || !($count=count($_POST['tids'])))
                $errors['err'] = sprintf(
                        __('You must select at least %s.'),
                        __('one ticket'));
        } else {
            $count  =  $_REQUEST['count'];
        }
        switch ($action) {
        case 'merge':
        case 'link':
            $inc = 'merge-tickets.tmpl.php';
            $ticketIds = $_GET ? explode(',', $_GET['tids']) : explode(',', $_POST['tids']);
            $tickets = array();
            $title = strpos($_SERVER['PATH_INFO'], 'link') !== false ? 'link' : 'merge';
            $eventName = ($title && $title == 'link') ? 'linked' : 'merged';
            $permission = ($title && $title == 'link') ? (Ticket::PERM_LINK) : (Ticket::PERM_MERGE);
            $hasPermission = array();
            $parent = false;

            $tickets = Ticket::objects()
                ->filter(array('ticket_id__in'=>$ticketIds))
                ->values_flat('ticket_id', 'flags', 'dept_id', 'ticket_pid');
            foreach ($tickets as $ticket) {
                list($ticket_id, $flags, $dept_id, $ticket_pid) = $ticket;
                $mergeType = Ticket::getMergeTypeByFlag($flags);
                $isParent = Ticket::isParentStatic($flags);
                $role = $thisstaff->getRole($dept_id);
                $hasPermission[] = $role->hasPerm($permission);

                if (!$ticket)
                    continue;
                elseif (!$parent && $isParent && $mergeType != 'visual') {
                    $parent = $ticket;
                    $parentMergeType = $mergeType;
                }

                if ($mergeType != 'visual' && $title == 'link')
                    $info['error'] = sprintf(
                            __('One or more Tickets selected is part of a merge. Merged Tickets cannot be %s.'),
                            __($eventName)
                            );

                if ($parent && ($isParent && $mergeType != 'visual') && $parent[0] != $ticket_id)
                    $info['error'] = sprintf(
                            __('More than one Parent Ticket selected. %1$s cannot be %2$s.'),
                            _N('The selected Ticket', 'The selected Tickets', $count),
                            __($eventName)
                            );

                if ($ticket_pid && $mergeType != 'visual' && $title == 'merge')
                    $info['error'] = sprintf(
                            __('One or more Tickets selected is a merged child. %1$s cannot be %2$s.'),
                            _N('The selected Ticket', 'The selected Tickets', $count),
                            __($eventName)
                            );
            }
            //move parent ticket to top of list
            if (count($ticketIds) > 1) {
                $ticketIdsSorted = $ticketIds;
                if ($parent && $parentMergeType != 'visual') {
                    foreach ($ticketIdsSorted as $key => $value) {
                        if ($value == $parent[0]) {
                            unset($ticketIdsSorted[$key]);
                            array_unshift($ticketIdsSorted, $value);
                            array_unshift($ticketIdsSorted, new SqlField('ticket_id'));
                        }
                    }
                }

                $expr = call_user_func_array(array('SqlFunction', 'FIELD'), $ticketIdsSorted);
            }
            $tickets = Ticket::objects()
                 ->filter(array('ticket_id__in'=>$ticketIds))
                 ->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id',
                               'user_id', 'cdata__subject', 'user__name', 'flags')
                 ->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
                                  'collaborators' => SqlAggregate::COUNT('thread__collaborators__id'),
                                  'entries' => SqlAggregate::COUNT('thread__entries__id'),))
                 ->order_by($expr ?: 'sort');
            $ticket = Ticket::lookup($parent[0] ?: $ticket[0]);

            // Generic permission check.
            if (in_array(false, $hasPermission) && !$ticket->getThread()->isReferred()) {
                $info['error'] = sprintf(
                        __('You do not have permission to %1$s %2$s'),
                        __($title),
                        _N('the selected Ticket', 'the selected Tickets', $count));
                $info = array_merge($info, Format::htmlchars($_POST));
            } else
                $info['action'] = sprintf('#tickets/%s/merge', $ticket->getId());
            break;
        case 'claim':
            $w = 'me';
        case 'assign':
            $inc = 'assign.tmpl.php';
            $info[':action'] = "#tickets/mass/assign/$w";
            $info[':title'] = sprintf('Assign %s',
                    _N('selected ticket', 'selected tickets', $count));

            $form = AssignmentForm::instantiate($_POST);

            $assignCB = function($t, $f, $e) {
                return $t->assign($f, $e);
            };

            $assignees = null;
            switch ($w) {
                case 'agents':
                    $depts = array();
                    $tids = $_POST['tids'] ?: array_filter(explode(',', $_REQUEST['tids']));
                    if ($tids) {
                        $tickets = Ticket::objects()
                            ->distinct('dept_id')
                            ->filter(array('ticket_id__in' => $tids));

                        $depts = $tickets->values_flat('dept_id');
                    }
                    //agents in depts $thisstaff can access
                    $members = $thisstaff->getDeptAgents(array('available' => true));

                    if ($depts) {
                        $all_agent_depts = Dept::objects()->filter(
                            Q::all( array('id__in' => $depts,
                            Q::not(array('flags__hasbit'
                                => Dept::FLAG_ASSIGN_MEMBERS_ONLY)),
                            Q::not(array('flags__hasbit'
                                => Dept::FLAG_ASSIGN_PRIMARY_ONLY))
                            )))->values_flat('id');
                        if (!count($all_agent_depts)) {
                            $members->filter(Q::any( array(
                                        'dept_id__in' => $depts,
                                        Q::all(array(
                                            'dept_access__dept__id__in' => $depts,
                                            Q::not(array('dept_access__dept__flags__hasbit'
                                                => Dept::FLAG_ASSIGN_MEMBERS_ONLY,
                                                'dept_access__dept__flags__hasbit'
                                                    => Dept::FLAG_ASSIGN_PRIMARY_ONLY))
                                            ))
                                        )));
                        }
                    }

                    switch ($cfg->getAgentNameFormat()) {
                    case 'last':
                    case 'lastfirst':
                    case 'legal':
                        $members->order_by('lastname', 'firstname');
                        break;

                    default:
                        $members->order_by('firstname', 'lastname');
                    }

                    $prompt  = __('Select an Agent');
                    $assignees = array();
                    foreach ($members as $member)
                         $assignees['s'.$member->getId()] = $member->getName();

                    if (!$assignees)
                        $info['warn'] =  __('No agents available for assignment');
                    break;
                case 'teams':
                    $assignees = array();
                    $prompt = __('Select a Team');
                    foreach (Team::getActiveTeams() as $id => $name)
                        $assignees['t'.$id] = $name;

                    if (!$assignees)
                        $info['warn'] =  __('No teams available for assignment');
                    break;
                case 'me':
                    $info[':action'] = '#tickets/mass/claim';
                    $info[':title'] = sprintf('Claim %s',
                            _N('selected ticket', 'selected tickets', $count));
                    $info['warn'] = sprintf(
                            __('Are you sure you want to CLAIM %s?'),
                            _N('selected ticket', 'selected tickets', $count));
                    $verb = sprintf('%s, %s', __('Yes'), __('Claim'));
                    $id = sprintf('s%s', $thisstaff->getId());
                    $assignees = array($id => $thisstaff->getName());
                    $vars = $_POST ?: array('assignee' => array($id));
                    $form = ClaimForm::instantiate($vars);
                    $assignCB = function($t, $f, $e) {
                        return $t->claim($f, $e);
                    };
                    break;
            }

            if ($assignees != null)
                $form->setAssignees($assignees);

            if ($prompt && ($f=$form->getField('assignee')))
                $f->configure('prompt', $prompt);

            if ($_POST && $form->isValid()) {
                // we need to clear this relation so we can create a fresh
                // query that will get roles for all depts this agent can access
                unset($thisstaff->ht['dept_access']);
                foreach ($_POST['tids'] as $tid) {
                    if (($t=Ticket::lookup($tid))
                            // Make sure the agent is allowed to
                            // access and assign the task.
                            && $t->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
                            // Do the assignment
                            && $assignCB($t, $form, $e)
                            )
                        $i++;
                }

                if (!$i) {
                    $info['error'] = sprintf(
                            __('Unable to %1$s %2$s'),
                            __('assign'),
                            _N('selected ticket', 'selected tickets', $count));
                }
            }
            break;
        case 'transfer':
            $inc = 'transfer.tmpl.php';
            $info[':action'] = '#tickets/mass/transfer';
            $info[':title'] = sprintf(__('Transfer %s'),
                    _N('selected ticket', 'selected tickets', $count));
            $form = TransferForm::instantiate($_POST);
            $form->hideDisabled();
            if ($_POST && $form->isValid()) {
                foreach ($_POST['tids'] as $tid) {
                    if (($t=Ticket::lookup($tid))
                            // Make sure the agent is allowed to
                            // access and transfer the task.
                            && $t->checkStaffPerm($thisstaff, Ticket::PERM_TRANSFER)
                            // Do the transfer
                            && $t->transfer($form, $e)
                            )
                        $i++;
                }

                if (!$i) {
                    $info['error'] = sprintf(
                            __('Unable to %1$s %2$s'),
                            __('transfer'),
                            _N('selected ticket', 'selected tickets', $count));
                }
            }
            break;
        case 'delete':
            $inc = 'delete.tmpl.php';
            $info[':action'] = '#tickets/mass/delete';
            $info[':title'] = sprintf('Delete %s',
                    _N('selected ticket', 'selected tickets', $count));

            $info[':placeholder'] = sprintf(__(
                        'Optional reason for deleting %s'),
                    _N('selected ticket', 'selected tickets', $count));
            $info['warn'] = sprintf(__(
                        'Are you sure you want to DELETE %s?'),
                    _N('selected ticket', 'selected tickets', $count));
            $info[':extra'] = sprintf('<strong>%s</strong>',
                        __('Deleted tickets CANNOT be recovered, including any associated attachments.')
                        );

            // Generic permission check.
            if (!$thisstaff->hasPerm(Ticket::PERM_DELETE, false))
                $errors['err'] = sprintf(
                        __('You do not have permission %s'),
                        __('to delete tickets'));

            if ($_POST && !$errors) {
                foreach ($_POST['tids'] as $tid) {
                    if (($t=Ticket::lookup($tid))
                            && $t->checkStaffPerm($thisstaff, Ticket::PERM_DELETE)
                            && $t->delete($_POST['comments'], $e)
                            )
                        $i++;
                }

                if (!$i) {
                    $info['error'] = sprintf(
                            __('Unable to %1$s %2$s'),
                            __('delete'),
                            _N('selected ticket', 'selected tickets', $count));
                }
            }
            break;
        default:
            Http::response(404, __('Unknown action'));
        }

        if ($_POST && $i) {

            // Assume success
            if ($i==$count) {
                $msg = sprintf(__('Successfully %1$s %2$s.' /* Tokens are <actioned> <x selected ticket(s)> */ ),
                        $actions[$action]['verbed'],
                        sprintf('%1$d %2$s',
                            $count,
                            _N('selected ticket', 'selected tickets', $count))
                        );
                $_SESSION['::sysmsgs']['msg'] = $msg;
            } else {
                $warn = sprintf(
                        __('%1$d of %2$d %3$s %4$s'
                        /* Tokens are <x> of <y> <selected ticket(s)> <actioned> */),
                        $i, $count,
                        _N('selected ticket', 'selected tickets',
                            $count),
                        $actions[$action]['verbed']);
                $_SESSION['::sysmsgs']['warn'] = $warn;
            }
            Http::response(201, 'processed');
        } elseif($_POST && !isset($info['error'])) {
            $info['error'] = $errors['err'] ?: sprintf(
                    __('Unable to %1$s %2$s'),
                    __('process'),
                    _N('selected ticket', 'selected tickets', $count));
        }

        if ($_POST)
            $info = array_merge($info, Format::htmlchars($_POST));

        include STAFFINC_DIR . "templates/$inc";
        //  Copy checked tickets to the form.
        echo "
        <script type=\"text/javascript\">
        $(function() {
            $('form#tickets input[name=\"tids[]\"]:checkbox:checked')
            .each(function() {
                $('<input>')
                .prop('type', 'hidden')
                .attr('name', 'tids[]')
                .val($(this).val())
                .appendTo('form.mass-action');
            });
        });
        </script>";

    }

    function changeTicketStatus($tid, $status, $id=0) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, 'Access denied');
        elseif (!$tid
                || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket #');

        $role = $ticket->getRole($thisstaff);

        $info = array();
        $state = null;
        switch($status) {
            case 'open':
            case 'reopen':
                $state = 'open';
                break;
            case 'close':
                if (!$role->hasPerm(Ticket::PERM_CLOSE))
                    Http::response(403, 'Access denied');
                $state = 'closed';

                // Check if ticket is closeable
                if (is_string($closeable=$ticket->isCloseable()))
                    $info['warn'] =  $closeable;

                break;
            case 'delete':
                if (!$role->hasPerm(Ticket::PERM_DELETE))
                    Http::response(403, 'Access denied');
                $state = 'deleted';
                break;
            default:
                $state = $ticket->getStatus()->getState();
                $info['warn'] = sprintf(__('%s: Unknown or invalid'),
                        __('status'));
        }

        $info['status_id'] = $id ?: $ticket->getStatusId();

        return self::_changeTicketStatus($ticket, $state, $info);
    }

    function setTicketStatus($tid) {
        global $thisstaff, $ost;

        if (!$thisstaff)
            Http::response(403, 'Access denied');
        elseif (!$tid
                || !($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket #');

        $errors = $info = array();
        if (!$_POST['status_id']
                || !($status= TicketStatus::lookup($_POST['status_id'])))
            $errors['status_id'] = sprintf('%s %s',
                    __('Unknown or invalid'), __('status'));
        elseif ($status->getId() == $ticket->getStatusId())
            $errors['err'] = sprintf(__('Ticket already set to %s status'),
                    __($status->getName()));
        elseif (($role = $ticket->getRole($thisstaff))) {
            // Make sure the agent has permission to set the status
            switch(mb_strtolower($status->getState())) {
                case 'open':
                    if (!$role->hasPerm(Ticket::PERM_CLOSE)
                            && !$role->hasPerm(Ticket::PERM_CREATE))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to reopen tickets'));
                    break;
                case 'closed':
                    if (!$role->hasPerm(Ticket::PERM_CLOSE))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to resolve/close tickets'));
                    break;
                case 'deleted':
                    if (!$role->hasPerm(Ticket::PERM_DELETE))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to archive/delete tickets'));
                    break;
                default:
                    $errors['err'] = sprintf('%s %s',
                            __('Unknown or invalid'), __('status'));
            }
        } else {
            $errors['err'] = __('Access denied');
        }

        $state = strtolower($status->getState());

        if (!$errors && $ticket->setStatus($status, $_REQUEST['comments'], $errors)) {
            $failures = array();
            // Set children statuses (if applicable)
            if ($_REQUEST['children']) {
                $children = $ticket->getChildren();

                foreach ($children as $cid) {
                    $child = Ticket::lookup($cid[0]);
                    if (!$child->setStatus($status, '', $errors))
                        $failures[$cid[0]] = $child->getNumber();
                }
            }

            if (!$failures) {
                if ($state == 'deleted') {
                    $msg = sprintf('%s %s',
                            sprintf(__('Ticket #%s'), $ticket->getNumber()),
                            __('deleted sucessfully')
                            );
                } elseif ($state != 'open') {
                     $msg = sprintf(__('%s status changed to %s'),
                             sprintf(__('Ticket #%s'), $ticket->getNumber()),
                             $status->getName());
                } else {
                    $msg = sprintf(
                            __('%s status changed to %s'),
                            __('Ticket'),
                            $status->getName());
                }
            } else {
                $tickets = array();
                foreach ($failures as $id=>$num) {
                    $tickets[] = sprintf('<a href="tickets.php?id=%d"><b>#%s</b></a>',
                                    $id,
                                    $num);
                }
                $info['warn'] = sprintf(__('Error updating ticket status for %s'),
                                 ($tickets) ? implode(', ', $tickets) : __('child tickets')
                                 );
            }
            $_SESSION['::sysmsgs']['msg'] = $msg;

            Http::response(201, 'Successfully processed');
        } elseif (!$errors['err']) {
            $errors['err'] =  __('Error updating ticket status');
        }

        $state = $state ?: $ticket->getStatus()->getState();
        $info['status_id'] = $status
            ? $status->getId() : $ticket->getStatusId();

        return self::_changeTicketStatus($ticket, $state, $info, $errors);
    }

    function changeSelectedTicketsStatus($status, $id=0) {
        global $thisstaff, $cfg;

        if (!$thisstaff)
            Http::response(403, 'Access denied');

        $state = null;
        $info = array();
        switch($status) {
            case 'open':
            case 'reopen':
                $state = 'open';
                break;
            case 'close':
                if (!$thisstaff->hasPerm(Ticket::PERM_CLOSE, false))
                    Http::response(403, 'Access denied');
                $state = 'closed';
                break;
            case 'delete':
                if (!$thisstaff->hasPerm(Ticket::PERM_DELETE, false))
                    Http::response(403, 'Access denied');

                $state = 'deleted';
                break;
            default:
                $info['warn'] = sprintf('%s %s',
                        __('Unknown or invalid'), __('status'));
        }

        $info['status_id'] = $id;

        return self::_changeSelectedTicketsStatus($state, $info);
    }

    function setSelectedTicketsStatus($state) {
        global $thisstaff, $ost;

        $errors = $info = array();
        if (!$thisstaff || !$thisstaff->canManageTickets())
            $errors['err'] = sprintf('%s %s',
                    sprintf(__('You do not have permission %s'),
                        __('to mass manage tickets')),
                    __('Contact admin for such access'));
        elseif (!$_REQUEST['tids'] || !count($_REQUEST['tids']))
            $errors['err']=sprintf(__('You must select at least %s.'),
                    __('one ticket'));
        elseif (!($status= TicketStatus::lookup($_REQUEST['status_id'])))
            $errors['status_id'] = sprintf('%s %s',
                    __('Unknown or invalid'), __('status'));
        elseif (!$errors) {
            // Make sure the agent has permission to set the status
            switch(mb_strtolower($status->getState())) {
                case 'open':
                    if (!$thisstaff->hasPerm(Ticket::PERM_CLOSE, false)
                            && !$thisstaff->hasPerm(Ticket::PERM_CREATE, false))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to reopen tickets'));
                    break;
                case 'closed':
                    if (!$thisstaff->hasPerm(Ticket::PERM_CLOSE, false))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to resolve/close tickets'));
                    break;
                case 'deleted':
                    if (!$thisstaff->hasPerm(Ticket::PERM_DELETE, false))
                        $errors['err'] = sprintf(__('You do not have permission %s'),
                                __('to archive/delete tickets'));
                    break;
                default:
                    $errors['err'] = sprintf('%s %s',
                            __('Unknown or invalid'), __('status'));
            }
        }

        $count = count($_REQUEST['tids']);
        if (!$errors) {
            $i = 0;
            $comments = $_REQUEST['comments'];
            foreach ($_REQUEST['tids'] as $tid) {

                if (($ticket=Ticket::lookup($tid))
                        && $ticket->getStatusId() != $status->getId()
                        && $ticket->checkStaffPerm($thisstaff)
                        && $ticket->setStatus($status, $comments, $errors))
                    $i++;
            }

            if (!$i) {
                $errors['err'] = $errors['err']
                    ?: sprintf(__('Unable to change status for %s'),
                        _N('selected ticket', 'selected tickets', $count));
            }
            else {
                // Assume success
                if ($i==$count) {

                    if (!strcasecmp($status->getState(), 'deleted')) {
                        $msg = sprintf(__( 'Successfully deleted %s.'),
                                _N('selected ticket', 'selected tickets',
                                    $count));
                    } else {
                       $msg = sprintf(
                            __(
                                /* 1$ will be 'selected ticket(s)', 2$ is the new status */
                                'Successfully changed status of %1$s to %2$s'),
                            _N('selected ticket', 'selected tickets',
                                $count),
                            $status->getName());
                    }

                    $_SESSION['::sysmsgs']['msg'] = $msg;
                } else {

                    if (!strcasecmp($status->getState(), 'deleted')) {
                        $warn = sprintf(__('Successfully deleted %s.'),
                                sprintf(__('%1$d of %2$d selected tickets'),
                                    $i, $count)
                                );
                    } else {

                        $warn = sprintf(
                                __('%1$d of %2$d %3$s status changed to %4$s'),$i, $count,
                                _N('selected ticket', 'selected tickets',
                                    $count),
                                $status->getName());
                    }

                    $_SESSION['::sysmsgs']['warn'] = $warn;
                }

                Http::response(201, 'Successfully processed');
            }
        }

        return self::_changeSelectedTicketsStatus($state, $info, $errors);
    }

    function markAs($tid, $action='') {
        global $thisstaff;

        // Standard validation
        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, __('No such ticket'));

        if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_MARKANSWERED) && !$thisstaff->isManager($ticket->getDept()))
            Http::response(403, __('Permission denied'));

        $errors = array();
        $info = array(':title' => __('Please Confirm'));

        // Instantiate form for comment field
        $form = MarkAsForm::instantiate($_POST);

        // Mark as answered or unanswered
        if ($_POST) {
            switch($action) {
                case 'answered':
                    if($ticket->isAnswered())
                        $errors['err'] = __('Ticket is already marked as answered');
                    elseif (!$ticket->markAnswered())
                        $errors['err'] = __('Cannot mark ticket as answered');
                    break;

                case 'unanswered':
                    if(!$ticket->isAnswered())
                        $errors['err'] = __('Ticket is already marked as unanswered');
                    elseif (!$ticket->markUnAnswered())
                        $errors['err'] - __('Cannot mark ticket as unanswered');
                    break;

                default:
                    Http::response(404, __('Unknown action'));
            }

            // Retrun errors to form (if any)
            if($errors) {
                $info['error'] = $errors['err'] ?: sprintf(__('Unable to mark ticket as %s'), $action);
                $form->addErrors($errors);
            } else {
                // Add comment (if provided)
                $comments = $form->getComments();
                if ($comments) {
                    $title = __(sprintf('Ticket Marked %s', ucfirst($action)));
                    $_errors = array();

                    $ticket->postNote(
                        array('note' => $comments, 'title' => $title),
                        $_errors, $thisstaff, false);
                }

                // Add success messages and log activity
                $_SESSION['::sysmsgs']['msg'] = sprintf(__('Ticket marked as %s successfully'), $action);
                $msg = sprintf(__('Ticket flagged as %s by %s'), $action, $thisstaff->getName());
                $ticket->logActivity(sprintf(__('Ticket Marked %s'), ucfirst($action)), $msg);
                Http::response(201, $ticket->getId());
            }
        }

        include STAFFINC_DIR . 'templates/mark-as.tmpl.php';
    }

    function triggerThreadAction($ticket_id, $thread_id, $action) {
        $thread = ThreadEntry::lookup($thread_id);
        if (!$thread)
            Http::response(404, 'No such ticket thread entry');
        if ($thread->getThread()->getObjectId() != $ticket_id)
            Http::response(404, 'No such ticket thread entry');

        $valid = false;
        foreach ($thread->getActions() as $group=>$list) {
            foreach ($list as $name=>$A) {
                if ($A->getId() == $action) {
                    $valid = true; break;
                }
            }
        }
        if (!$valid)
            Http::response(400, 'Not a valid action for this thread');

        $thread->triggerAction($action);
    }

    private static function _changeSelectedTicketsStatus($state, $info=array(), $errors=array()) {

        $count = $_REQUEST['count'] ?:
            ($_REQUEST['tids'] ?  count($_REQUEST['tids']) : 0);

        $info['title'] = sprintf(__('Change Status &mdash; %1$d %2$s selected'),
                 $count,
                 _N('ticket', 'tickets', $count)
                 );

        if (!strcasecmp($state, 'deleted')) {

            $info['warn'] = sprintf(__(
                        'Are you sure you want to DELETE %s?'),
                    _N('selected ticket', 'selected tickets', $count)
                    );

            $info['extra'] = sprintf('<strong>%s</strong>', __(
                        'Deleted tickets CANNOT be recovered, including any associated attachments.')
                    );

            $info['placeholder'] = sprintf(__(
                        'Optional reason for deleting %s'),
                    _N('selected ticket', 'selected tickets', $count));
        }

        $info['status_id'] = $info['status_id'] ?: $_REQUEST['status_id'];
        $info['comments'] = Format::htmlchars($_REQUEST['comments']);

        return self::_changeStatus($state, $info, $errors);
    }

    private static function _changeTicketStatus($ticket, $state, $info=array(), $errors=array()) {

        $verb = TicketStateField::getVerb($state);

        $info['action'] = sprintf('#tickets/%d/status', $ticket->getId());
        $info['title'] = sprintf(__(
                    /* 1$ will be a verb, like 'open', 2$ will be the ticket number */
                    '%1$s Ticket #%2$s'),
                $verb ?: $state,
                $ticket->getNumber()
                );

        // Deleting?
        if (!strcasecmp($state, 'deleted')) {

            $info['placeholder'] = sprintf(__(
                        'Optional reason for deleting %s'),
                    __('this ticket'));
            $info[ 'warn'] = sprintf(__(
                        'Are you sure you want to DELETE %s?'),
                        __('this ticket'));
            //TODO: remove message below once we ship data retention plug
            $info[ 'extra'] = sprintf('<strong>%s</strong>',
                        __('Deleted tickets CANNOT be recovered, including any associated attachments.')
                        );
        }

        $info['status_id'] = $info['status_id'] ?: $ticket->getStatusId();
        $info['comments'] = Format::htmlchars($_REQUEST['comments']);

        // Has Children?
        $info['children'] = count($ticket->getChildren());

        return self::_changeStatus($state, $info, $errors);
    }

    private static function _changeStatus($state, $info=array(), $errors=array()) {

        if ($info && isset($info['errors']))
            $errors = array_merge($errors, $info['errors']);

        if (!$info['error'] && isset($errors['err']))
            $info['error'] = $errors['err'];

        include(STAFFINC_DIR . 'templates/ticket-status.tmpl.php');
    }

    function tasks($tid) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket');

         include STAFFINC_DIR . 'ticket-tasks.inc.php';
    }

    function relations($tid) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket');

         include STAFFINC_DIR . 'ticket-relations.inc.php';
    }

    function addTask($tid, $vars=array()) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid)))
            Http::response(404, 'Unknown ticket');

        if (!$ticket->checkStaffPerm($thisstaff, Task::PERM_CREATE))
            Http::response(403, 'Permission denied');

        $info=$errors=array();

        // Internal form
        $iform = TaskForm::getInternalForm($_POST);
        // Due date must be before tickets due date
        if ($ticket && $ticket->getEstDueDate()
                &&  Misc::db2gmtime($ticket->getEstDueDate()) > Misc::gmtime()
                && ($f=$iform->getField('duedate'))) {
            $f->configure('max', Misc::db2gmtime($ticket->getEstDueDate()));
        }
        $vars = array_merge($_SESSION[':form-data'] ?: array(), $vars);

        if ($_POST) {
            Draft::deleteForNamespace(
                    sprintf('ticket.%d.task', $ticket->getId()),
                    $thisstaff->getId());
            // Default form
            $form = TaskForm::getInstance();
            $form->setSource($_POST);

            $isvalid = true;
            if (!$iform->isValid())
                $isvalid = false;
            if (!$form->isValid())
                $isvalid = false;

            if ($isvalid) {
                $vars = $_POST;
                $vars['object_id'] = $ticket->getId();
                $vars['object_type'] = ObjectModel::OBJECT_TYPE_TICKET;
                $vars['default_formdata'] = $form->getClean();
                $vars['internal_formdata'] = $iform->getClean();
                $desc = $form->getField('description');
                $vars['description'] = $desc->getClean();
                if ($desc
                        && $desc->isAttachmentsEnabled()
                        && ($attachments=$desc->getWidget()->getAttachments()))
                    $vars['files'] = $attachments->getFiles();
                $vars['staffId'] = $thisstaff->getId();
                $vars['poster'] = $thisstaff;
                $vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
                if (($task=Task::create($vars, $errors))) {

                  if ($_SESSION[':form-data']['eid']) {
                    //add internal note to ticket:
                    $taskLink = sprintf('<a href="tasks.php?id=%d"><b>#%s</b></a>',
                        $task->getId(),
                        $task->getNumber());

                    $entryLink = sprintf('<a href="#entry-%d"><b>%s</b></a>',
                        $_SESSION[':form-data']['eid'],
                        Format::datetime($_SESSION[':form-data']['timestamp']));

                    $note = array(
                            'title' => __('Task Created From Thread Entry'),
                            'body' => sprintf(__(
                                // %1$s is the task ID number and %2$s is the thread
                                // entry date
                                'Task %1$s<br/> Thread Entry: %2$s'),
                                $taskLink, $entryLink)
                            );

                  $ticket->logNote($note['title'], $note['body'], $thisstaff);

                    //add internal note to task:
                    $ticketLink = sprintf('<a href="tickets.php?id=%d"><b>#%s</b></a>',
                        $ticket->getId(),
                        $ticket->getNumber());

                    $note = array(
                            'title' => __('Task Created From Thread Entry'),
                            'note' => sprintf(__('This Task was created from Ticket %1$s'), $ticketLink),
                    );

                    $task->postNote($note, $errors, $thisstaff);
                  }
                }

                  Http::response(201, $task->getId());
            }

            $info['error'] = sprintf('%s - %s', __('Error adding task'), __('Please try again!'));
        }

        $info['action'] = sprintf('#tickets/%d/add-task', $ticket->getId());
        $info['title'] = sprintf(
                __( 'Ticket #%1$s: %2$s'),
                $ticket->getNumber(),
                __('Add New Task')
                );

         include STAFFINC_DIR . 'templates/task.tmpl.php';
    }

    function task($tid, $id) {
        global $thisstaff;

        if (!($ticket=Ticket::lookup($tid))
                || !$ticket->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown ticket');

        // Lookup task and check access
        if (!($task=Task::lookup($id))
                || !$task->checkStaffPerm($thisstaff))
            Http::response(404, 'Unknown task');

        $info = $errors = array();
        $note_attachments_form = new SimpleForm(array(
            'attachments' => new FileUploadField(array('id'=>'attach',
                'name'=>'attach:note',
                'configuration' => array('extensions'=>'')))
        ));

        $reply_attachments_form = new SimpleForm(array(
            'attachments' => new FileUploadField(array('id'=>'attach',
                'name'=>'attach:reply',
                'configuration' => array('extensions'=>'')))
        ));

        if ($_POST) {
            $vars = $_POST;
            switch ($_POST['a']) {
            case 'postnote':
                $attachments = $note_attachments_form->getField('attachments')->getFiles();
                $vars['files'] = array_merge(
                    $vars['files'] ?: array(), $attachments);
                if (($note=$task->postNote($vars, $errors, $thisstaff))) {
                    $msg=__('Note posted successfully');
                    // Clear attachment list
                    $note_attachments_form->setSource(array());
                    $note_attachments_form->getField('attachments')->reset();
                    Draft::deleteForNamespace('task.note.'.$task->getId(),
                            $thisstaff->getId());
                } else {
                    if (!$errors['err'])
                        $errors['err'] = __('Unable to post the note - missing or invalid data.');
                }
                break;
            case 'postreply':
                $attachments = $reply_attachments_form->getField('attachments')->getFiles();
                $vars['files'] = array_merge(
                    $vars['files'] ?: array(), $attachments);
                if (($response=$task->postReply($vars, $errors))) {
                    $msg=__('Update posted successfully');
                    // Clear attachment list
                    $reply_attachments_form->setSource(array());
                    $reply_attachments_form->getField('attachments')->reset();
                    Draft::deleteForNamespace('task.response.'.$task->getId(),
                            $thisstaff->getId());
                } else {
                    if (!$errors['err'])
                        $errors['err'] = __('Unable to post the reply - missing or invalid data.');
                }
                break;
            default:
                $errors['err'] = __('Unknown action');
            }
        }

        include STAFFINC_DIR . 'templates/task-view.tmpl.php';
    }


    function export($id) {
        global $thisstaff;

        if (is_numeric($id))
            $queue = SavedSearch::lookup($id);
        else
            $queue = AdhocSearch::load($id);

       if (!$queue)
           Http::response(404, 'Unknown Queue');

        return $this->queueExport($queue);
    }

    function queueExport(CustomQueue $queue) {
        global $thisstaff;

        if (!$thisstaff)
            Http::response(403, 'Agent login is required');
        elseif (!$queue || !$queue->checkAccess($thisstaff))
            Http::response(404, 'No such saved queue');

        $errors = array();
        if ($_POST && is_array($_POST['fields'])) {
            // Cache export preferences
            $id = $queue->getId();
            $_SESSION['Export:Q'.$id]['fields'] = $_POST['fields'];
            $_SESSION['Export:Q'.$id]['filename'] = $_POST['filename'];
            $_SESSION['Export:Q'.$id]['delimiter'] = $_POST['csv-delimiter'];
            // Save fields selection if requested
            if ($queue->isSaved() && isset($_POST['save-changes']))
               $queue->updateExports(array_flip($_POST['fields']));

            // Filename of the report
            if (isset($_POST['filename'])
                    && ($parts = pathinfo($_POST['filename']))) {
                $filename = $_POST['filename'];
                if (strcasecmp($parts['extension'], 'csv'))
                      $filename ="$filename.csv";
            } else {
                $filename = sprintf('%s Tickets-%s.csv',
                        $queue->getName(),
                        date('Ymd'));
            }

            try {
                $interval = 5;
                $options = ['filename' => $filename,
                    'interval' => $interval, 'delimiter' => $_POST['csv-delimiter']];
                // Create desired exporter
                $exporter = new CsvExporter($options);
                // Acknowledge the export
                $exporter->ack();
                // Phew... now we're free to do the export
                // Ask the queue to export to the exporter
                $queue->export($exporter);
                $exporter->finalize();
                // Email the export if it exists
                $exporter->email($thisstaff);
                // Delete the file.
                @$exporter->delete();
                exit;
            } catch (Exception $ex) {
                $errors['err'] = __('Unable to prepare the export');
            }
        }

        include STAFFINC_DIR . 'templates/queue-export.tmpl.php';

    }
}
?>

/include/api.tickets.php
<?php

include_once INCLUDE_DIR.'class.api.php';
include_once INCLUDE_DIR.'class.ticket.php';

class TicketApiController extends ApiController {

    # Supported arguments -- anything else is an error. These items will be
    # inspected _after_ the fixup() method of the ApiXxxDataParser classes
    # so that all supported input formats should be supported
    function getRequestStructure($format, $data=null) {
        $supported = array(
            "alert", "autorespond", "source", "topicId",
            "attachments" => array("*" =>
                array("name", "type", "data", "encoding", "size")
            ),
            "message", "ip", "priorityId",
            "system_emails" => array(
                "*" => "*"
            ),
            "thread_entry_recipients" => array (
                "*" => array("to", "cc")
            )
        );
        # Fetch dynamic form field names for the given help topic and add
        # the names to the supported request structure
        if (isset($data['topicId'])
                && ($topic = Topic::lookup($data['topicId']))
                && ($forms = $topic->getForms())) {
            foreach ($forms as $form)
                foreach ($form->getDynamicFields() as $field)
                    $supported[] = $field->get('name');
        }

        # Ticket form fields
        # TODO: Support userId for existing user
        if(($form = TicketForm::getInstance()))
            foreach ($form->getFields() as $field)
                $supported[] = $field->get('name');

        # User form fields
        if(($form = UserForm::getInstance()))
            foreach ($form->getFields() as $field)
                $supported[] = $field->get('name');

        if(!strcasecmp($format, 'email')) {
            $supported = array_merge($supported, array('header', 'mid',
                'emailId', 'to-email-id', 'ticketId', 'reply-to', 'reply-to-name',
                'in-reply-to', 'references', 'thread-type', 'system_emails',
                'mailflags' => array('bounce', 'auto-reply', 'spam', 'viral'),
                'recipients' => array('*' => array('name', 'email', 'source'))
                ));

            $supported['attachments']['*'][] = 'cid';
        }

        return $supported;
    }

    /*
     Validate data - overwrites parent's validator for additional validations.
    */
    function validate(&$data, $format, $strict=true) {
        global $ost;

        //Call parent to Validate the structure
        if(!parent::validate($data, $format, $strict) && $strict)
            $this->exerr(400, __('Unexpected or invalid data received'));

        // Use the settings on the thread entry on the ticket details
        // form to validate the attachments in the email
        $tform = TicketForm::objects()->one()->getForm();
        $messageField = $tform->getField('message');
        $fileField = $messageField->getWidget()->getAttachments();

        // Nuke attachments IF API files are not allowed.
        if (!$messageField->isAttachmentsEnabled())
            $data['attachments'] = array();

        //Validate attachments: Do error checking... soft fail - set the error and pass on the request.
        if (isset($data['attachments']) && is_array($data['attachments'])) {
            foreach($data['attachments'] as &$file) {
                if ($file['encoding'] && !strcasecmp($file['encoding'], 'base64')) {
                    if(!($file['data'] = base64_decode($file['data'], true)))
                        $file['error'] = sprintf(__('%s: Poorly encoded base64 data'),
                            Format::htmlchars($file['name']));
                }
                // Validate and save immediately
                try {
                    $F = $fileField->uploadAttachment($file);
                    $file['id'] = $F->getId();
                }
                catch (FileUploadError $ex) {
                    $name = $file['name'];
                    $file = array();
                    $file['error'] = Format::htmlchars($name) . ': ' . $ex->getMessage();
                }
            }
            unset($file);
        }

        return true;
    }


    function create($format) {

        if (!($key=$this->requireApiKey()) || !$key->canCreateTickets())
            return $this->exerr(401, __('API key not authorized'));

        $ticket = null;
        if (!strcasecmp($format, 'email')) {
            // Process remotely piped emails - could be a reply...etc.
            $ticket = $this->processEmailRequest();
        } else {
            // Get and Parse request body data for the format
            $ticket = $this->createTicket($this->getRequest($format));
        }



        if ($ticket)
            $this->response(201, $ticket->getNumber());
        else
            $this->exerr(500, _S("unknown error"));

    }

    /* private helper functions */

    function createTicket($data, $source = 'API') {

        # Pull off some meta-data
        $alert       = (bool) (isset($data['alert'])       ? $data['alert']       : true);
        $autorespond = (bool) (isset($data['autorespond']) ? $data['autorespond'] : true);

        // Assign default value to source if not defined, or defined as NULL
        $data['source'] ??= $source;

        // Create the ticket with the data (attempt to anyway)
        $errors = array();
        if (($ticket = Ticket::create($data, $errors, $data['source'],
                        $autorespond, $alert)) &&  !$errors)
            return $ticket;

        // Ticket create failed Bigly - got errors?
        $title = null;
        // Got errors?
        if (count($errors)) {
            // Ticket denied? Say so loudly so it can standout from generic
            // validation errors
            if (isset($errors['errno']) && $errors['errno'] == 403) {
                $title = _S('Ticket denied');
                $error = sprintf("%s: %s\n\n%s",
                        $title, $data['email'], $errors['err']);
            } else {
                // unpack the errors
                $error = Format::array_implode("\n", "\n", $errors);
            }
        } else {
            // unknown reason - default
            $error = _S('unknown error');
        }

        $error = sprintf('%s :%s',
                _S('Unable to create new ticket'), $error);
        return $this->exerr($errors['errno'] ?: 500, $error, $title);
    }

    function processEmailRequest() {
        return $this->processEmail();
    }

    function processEmail($data=false, array $defaults = []) {

        try {
            if (!$data)
                $data = $this->getEmailRequest();
            elseif (!is_array($data))
                $data = $this->parseEmail($data);
        } catch (Exception $ex)  {
            throw new EmailParseError($ex->getMessage());
        }

        $data = array_merge($defaults, $data);
        $seen = false;
        if (($entry = ThreadEntry::lookupByEmailHeaders($data, $seen))
            && ($message = $entry->postEmail($data))
        ) {
            if ($message instanceof ThreadEntry) {
                return $message->getThread()->getObject();
            }
            else if ($seen) {
                // Email has been processed previously
                return $entry->getThread()->getObject();
            }
        }

        // Allow continuation of thread without initial message or note
        elseif (($thread = Thread::lookupByEmailHeaders($data))
            && ($message = $thread->postEmail($data))
        ) {
            return $thread->getObject();
        }

        // All emails which do not appear to be part of an existing thread
        // will always create new "Tickets". All other objects will need to
        // be created via the web interface or the API
        try {
            return $this->createTicket($data, 'Email');
        } catch (TicketApiError $err) {
            // Check if the ticket was denied by a filter or banlist
            if ($err->isDenied() && $data['mid']) {
                // We need to log the Message-Id (mid) so we don't
                // process the same email again in subsequent fetches
                $entry = new ThreadEntry();
                $entry->logEmailHeaders(0, $data['mid']);
                // throw TicketDenied exception so the caller can handle it
                // accordingly
                throw new TicketDenied($err->getMessage());
            } else {
                // otherwise rethrow this bad baby as it is!
                throw $err;
            }
        }
    }
}

//Local email piping controller - no API key required!
class PipeApiController extends TicketApiController {

    // Overwrite grandparent's (ApiController) response method.
    function response($code, $resp) {

        // It's important to use postfix exit codes for local piping instead
        // of HTTP's so the piping script can process them accordingly
        switch($code) {
            case 201: //Success
                $exitcode = 0;
                break;
            case 400:
                $exitcode = 66;
                break;
            case 401: /* permission denied */
            case 403:
                $exitcode = 77;
                break;
            case 415:
            case 416:
            case 417:
            case 501:
                $exitcode = 65;
                break;
            case 503:
                $exitcode = 69;
                break;
            case 500: //Server error.
            default: //Temp (unknown) failure - retry
                $exitcode = 75;
        }
        //We're simply exiting - MTA will take care of the rest based on exit code!
        exit($exitcode);
    }

    static function process($sapi=null) {
        $pipe = new PipeApiController($sapi);
        if (($ticket=$pipe->processEmail()))
           return $pipe->response(201,
                   is_object($ticket) ? $ticket->getNumber() : $ticket);

        return $pipe->exerr(416, __('Request failed - retry again!'));
    }

    static function local() {
        return self::process('cli');
    }
}

class TicketApiError extends Exception {

    // Check if exception is because of denial
    public function isDenied() {
        return ($this->getCode() === 403);
    }
}

class TicketDenied extends Exception {}
class EmailParseError extends Exception {}

?>


/include/client/tickets.inc.php:
<?php
if(!defined('OSTCLIENTINC') || !is_object($thisclient) || !$thisclient->isValid()) die('Access Denied');

$settings = &$_SESSION['client:Q'];

// Unpack search, filter, and sort requests
if (isset($_REQUEST['clear']))
    $settings = array();
if (isset($_REQUEST['keywords'])) {
    $settings['keywords'] = $_REQUEST['keywords'];
}
if (isset($_REQUEST['topic_id'])) {
    $settings['topic_id'] = $_REQUEST['topic_id'];
}
if (isset($_REQUEST['status'])) {
    $settings['status'] = $_REQUEST['status'];
}

$org_tickets = $thisclient->canSeeOrgTickets();
if ($settings['keywords']) {
    // Don't show stat counts for searches
    $openTickets = $closedTickets = -1;
}
elseif ($settings['topic_id']) {
    $openTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'],
        'open', $org_tickets);
    $closedTickets = $thisclient->getNumTopicTicketsInState($settings['topic_id'],
        'closed', $org_tickets);
}
else {
    $openTickets = $thisclient->getNumOpenTickets($org_tickets);
    $closedTickets = $thisclient->getNumClosedTickets($org_tickets);
}

$tickets = Ticket::objects();

$qs = array();
$status=null;

$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 ?: $sortOptions['date'];
if ($_REQUEST['order'] && !is_null($orderWays[strtoupper($_REQUEST['order'])]))
    $order = $orderWays[strtoupper($_REQUEST['order'])];
else
    $order = $orderWays['DESC'];

$x=$sort.'_sort';
$$x=' class="'.strtolower($_REQUEST['order'] ?: 'desc').'" ';

$basic_filter = Ticket::objects();
if ($settings['topic_id']) {
    $basic_filter = $basic_filter->filter(array('topic_id' => $settings['topic_id']));
}

if ($settings['status'])
    $status = strtolower($settings['status']);
    switch ($status) {
    default:
        $status = 'open';
    case 'open':
    case 'closed':
		$results_type = ($status == 'closed') ? __('Closed Tickets') : __('Open Tickets');
        $basic_filter->filter(array('status__state' => $status));
        break;
}

// Add visibility constraints — use a union query to use multiple indexes,
// use UNION without "ALL" (false as second parameter to union()) to imply
// unique values
$visibility = $basic_filter->copy()
    ->values_flat('ticket_id')
    ->filter(array('user_id' => $thisclient->getId()));

// Add visibility of Tickets where the User is a Collaborator if enabled
if ($cfg->collaboratorTicketsVisibility())
    $visibility = $visibility
    ->union($basic_filter->copy()
        ->values_flat('ticket_id')
        ->filter(array('thread__collaborators__user_id' => $thisclient->getId()))
    , false);

if ($thisclient->canSeeOrgTickets()) {
    $visibility = $visibility->union(
        $basic_filter->copy()->values_flat('ticket_id')
            ->filter(array('user__org_id' => $thisclient->getOrgId()))
    , false);
}

// Perform basic search
if ($settings['keywords']) {
    $q = trim($settings['keywords']);
    if (is_numeric($q)) {
        $tickets->filter(array('number__startswith'=>$q));
    } elseif (strlen($q) > 2) { //Deep search!
        // Use the search engine to perform the search
        $tickets = $ost->searcher->find($q, $tickets);
    }
}

$tickets->distinct('ticket_id');

TicketForm::ensureDynamicDataView();

$total=$visibility->count();
$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
$qstr = '&amp;'. Http::build_query($qs);
$qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
$pageNav->setURL('tickets.php', $qs);
$tickets->filter(array('ticket_id__in' => $visibility));
$pageNav->paginate($tickets);

$showing =$total ? $pageNav->showing() : "";
if(!$results_type)
{
	$results_type=ucfirst($status).' '.__('Tickets');
}
$showing.=($status)?(' '.$results_type):' '.__('All Tickets');
if($search)
    $showing=__('Search Results').": $showing";

$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', 'user_id'
);

?>
<div class="search well">
<div class="flush-left">
<form action="tickets.php" method="get" id="ticketSearchForm">
    <input type="hidden" name="a"  value="search">
    <input type="text" name="keywords" size="30" value="<?php echo Format::htmlchars($settings['keywords']); ?>">
    <input type="submit" value="<?php echo __('Search');?>">
<div class="pull-right">
    <?php echo __('Help Topic'); ?>:
    <select name="topic_id" class="nowarn" onchange="javascript: this.form.submit(); ">
        <option value="">&mdash; <?php echo __('All Help Topics');?> &mdash;</option>
<?php
foreach (Topic::getHelpTopics(true) as $id=>$name) {
        $count = $thisclient->getNumTopicTickets($id, $org_tickets);
        if ($count == 0)
            continue;
?>
        <option value="<?php echo $id; ?>"i
            <?php if ($settings['topic_id'] == $id) echo 'selected="selected"'; ?>
            ><?php echo sprintf('%s (%d)', Format::htmlchars($name),
                $thisclient->getNumTopicTickets($id)); ?></option>
<?php } ?>
    </select>
</div>
</form>
</div>

<?php if ($settings['keywords'] || $settings['topic_id'] || $_REQUEST['sort']) { ?>
<div style="margin-top:10px"><strong><a href="?clear" style="color:#777"><i class="icon-remove-circle"></i> <?php echo __('Clear all filters and sort'); ?></a></strong></div>
<?php } ?>

</div>


<h1 style="margin:10px 0">
    <a href="<?php echo Http::refresh_url(); ?>"
        ><i class="refresh icon-refresh"></i>
    <?php echo __('Tickets'); ?>
    </a>

<div class="pull-right states">
    <small>
<?php if ($openTickets) { ?>
    <i class="icon-file-alt"></i>
    <a class="state <?php if ($status == 'open') echo 'active'; ?>"
        href="?<?php echo Http::build_query(array('a' => 'search', 'status' => 'open')); ?>">
    <?php echo __('Open'); if ($openTickets > 0) echo sprintf(' (%d)', $openTickets); ?>
    </a>
    <?php if ($closedTickets) { ?>
    &nbsp;
    <span style="color:lightgray">|</span>
    <?php }
}
if ($closedTickets) {?>
    &nbsp;
    <i class="icon-file-text"></i>
    <a class="state <?php if ($status == 'closed') echo 'active'; ?>"
        href="?<?php echo Http::build_query(array('a' => 'search', 'status' => 'closed')); ?>">
    <?php echo __('Closed'); if ($closedTickets > 0) echo sprintf(' (%d)', $closedTickets); ?>
    </a>
<?php } ?>
    </small>
</div>
</h1>
<table id="ticketTable" width="800" border="0" cellspacing="0" cellpadding="0">
    <caption><?php echo $showing; ?></caption>
    <thead>
        <tr>
            <th nowrap>
                <a href="tickets.php?sort=ID&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="<?php echo sprintf('%s %s', __('Sort By'), __('Ticket ID')); ?>"><?php echo __('Ticket #');?>&nbsp;<i class="icon-sort"></i></a>
            </th>
            <th width="120">
                <a href="tickets.php?sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="<?php echo sprintf('%s %s', __('Sort By'), __('Date')); ?>"><?php echo __('Create Date');?>&nbsp;<i class="icon-sort"></i></a>
            </th>
            <th width="100">
                <a href="tickets.php?sort=status&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="<?php echo sprintf('%s %s', __('Sort By'), __('Status')); ?>"><?php echo __('Status');?>&nbsp;<i class="icon-sort"></i></a>
            </th>
            <th width="320">
                <a href="tickets.php?sort=subject&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="<?php echo sprintf('%s %s', __('Sort By'), __('Subject')); ?>"><?php echo __('Subject');?>&nbsp;<i class="icon-sort"></i></a>
            </th>
            <th width="120">
                <a href="tickets.php?sort=dept&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="<?php echo sprintf('%s %s', __('Sort By'), __('Department')); ?>"><?php echo __('Department');?>&nbsp;<i class="icon-sort"></i></a>
            </th>
        </tr>
    </thead>
    <tbody>
    <?php
     $subject_field = TicketForm::objects()->one()->getField('subject');
     $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 = $subject_field->display(
                $subject_field->to_php($T['cdata__subject']) ?: $T['cdata__subject']
            );
            $status = TicketStatus::getLocalById($T['status_id'], 'value', $T['status__name']);
            if (false) // XXX: Reimplement attachment count support
                $subject.='  &nbsp;&nbsp;<span class="Icon file"></span>';

            $ticketNumber=$T['number'];
            if($T['isanswered'] && !strcasecmp($T['status__state'], 'open')) {
                $subject="<b>$subject</b>";
                $ticketNumber="<b>$ticketNumber</b>";
            }
            $thisclient->getId() != $T['user_id'] ? $isCollab = true : $isCollab = false;
            ?>
            <tr id="<?php echo $T['ticket_id']; ?>">
                <td>
                <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><?php echo Format::date($T['created']); ?></td>
                <td><?php echo $status; ?></td>
                <td>
                  <?php if ($isCollab) {?>
                    <div style="max-height: 1.2em; max-width: 320px;" class="link truncate" href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><i class="icon-group"></i> <?php echo $subject; ?></div>
                  <?php } else {?>
                    <div style="max-height: 1.2em; max-width: 320px;" class="link truncate" href="tickets.php?id=<?php echo $T['ticket_id']; ?>"><?php echo $subject; ?></div>
                    <?php } ?>
                </td>
                <td><span class="truncate"><?php echo $dept; ?></span></td>
            </tr>
        <?php
        }

     } else {
         echo '<tr><td colspan="5">'.__('Your query did not match any records').'</td></tr>';
     }
    ?>
    </tbody>
</table>
<?php
if ($total) {
    echo '<div>&nbsp;'.__('Page').':'.$pageNav->getPageLinks().'&nbsp;</div>';
}
?>


ticket-view.inc.php:
<?php
//Note that ticket obj is initiated in tickets.php.
if(!defined('OSTSCPINC') || !$thisstaff || !is_object($ticket) || !$ticket->getId()) die('Invalid path');

//Make sure the staff is allowed to access the page.
if(!@$thisstaff->isStaff() || !$ticket->checkStaffPerm($thisstaff)) die('Access Denied');

//Re-use the post info on error...savekeyboards.org (Why keyboard? -> some people care about objects than users!!)
$info=($_POST && $errors)?Format::input($_POST):array();

$type = array('type' => 'viewed');
Signal::send('object.view', $ticket, $type);

//Get the goodies.
$dept     = $ticket->getDept();  //Dept
$role     = $ticket->getRole($thisstaff);
$staff    = $ticket->getStaff(); //Assigned or closed by..
$user     = $ticket->getOwner(); //Ticket User (EndUser)
$team     = $ticket->getTeam();  //Assigned team.
$sla      = $ticket->getSLA();
$lock     = $ticket->getLock();  //Ticket lock obj
$children = $ticket->getChildren();
$thread = $ticket->getThread();
if (!$lock && $cfg->getTicketLockMode() == Lock::MODE_ON_VIEW)
    $lock = $ticket->acquireLock($thisstaff->getId());
$mylock = ($lock && $lock->getStaffId() == $thisstaff->getId()) ? $lock : null;
$id    = $ticket->getId();    //Ticket ID.
$isManager = $dept->isManager($thisstaff); //Check if Agent is Manager
$canRelease = ($isManager || $role->hasPerm(Ticket::PERM_RELEASE)); //Check if Agent can release tickets
$blockReply = $ticket->isChild() && $ticket->getMergeType() != 'visual';
$canMarkAnswered = ($isManager || $role->hasPerm(Ticket::PERM_MARKANSWERED)); //Check if Agent can mark as answered/unanswered

//Useful warnings and errors the user might want to know!
if ($ticket->isClosed() && !$ticket->isReopenable())
    $warn = sprintf(
            __('Current ticket status (%s) does not allow the end user to reply.'),
            $ticket->getStatus());
elseif ($blockReply)
    $warn = __('Child Tickets do not allow the end user or agent to reply.');
elseif ($ticket->isAssigned()
        && (($staff && $staff->getId()!=$thisstaff->getId())
            || ($team && !$team->hasMember($thisstaff))
        ))
    $warn.= sprintf('&nbsp;&nbsp;<span class="Icon assignedTicket">%s</span>',
            sprintf(__('Ticket is assigned to %s'),
                implode('/', $ticket->getAssignees())
                ));

if (!$errors['err']) {

    if ($lock && $lock->getStaffId()!=$thisstaff->getId())
        $errors['err'] = sprintf(__('%s is currently locked by %s'),
                __('This ticket'),
                $lock->getStaffName());
    elseif (($emailBanned=Banlist::isBanned($ticket->getEmail())))
        $errors['err'] = __('Email is in banlist! Must be removed before any reply/response');
    elseif (!Validator::is_valid_email($ticket->getEmail()))
        $errors['err'] = __('EndUser email address is not valid! Consider updating it before responding');
}

$unbannable=($emailBanned) ? BanList::includes($ticket->getEmail()) : false;

if($ticket->isOverdue())
    $warn.='&nbsp;&nbsp;<span class="Icon overdueTicket">'.__('Marked overdue!').'</span>';

?>
<div>
    <div id="msg_notice" style="display: none;"><span id="msg-txt"><?php echo $msg ?: ''; ?></span></div>
    <div class="sticky bar">
       <div class="content">
        <div class="pull-right flush-right">
            <?php
            if ($thisstaff->hasPerm(Email::PERM_BANLIST)
                    || $role->hasPerm(Ticket::PERM_EDIT)
                    || ($dept && $dept->isManager($thisstaff))) { ?>
            <span class="action-button pull-right" data-placement="bottom" data-dropdown="#action-dropdown-more" data-toggle="tooltip" title="<?php echo __('More');?>">
                <i class="icon-caret-down pull-right"></i>
                <span ><i class="icon-cog"></i></span>
            </span>
            <?php
            }

            if ($role->hasPerm(Ticket::PERM_EDIT)) { ?>
                <a class="action-button pull-right" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Edit'); ?>" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=edit"><i class="icon-edit"></i></a>
            <?php
            } ?>
            <span class="action-button pull-right" data-placement="bottom" data-dropdown="#action-dropdown-print" data-toggle="tooltip" title="<?php echo __('Print'); ?>">
                <i class="icon-caret-down pull-right"></i>
                <a id="ticket-print" aria-label="<?php echo __('Print'); ?>" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print"><i class="icon-print"></i></a>
            </span>
            <div id="action-dropdown-print" class="action-dropdown anchor-right">
              <ul>
                 <li title="PDF File"><a class="no-pjax" target="_blank" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print&notes=0&events=0"><i
                 class="icon-file-text-alt"></i> <?php echo __('Ticket Thread'); ?></a>
                 <li title="PDF File"><a class="no-pjax" target="_blank" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print&notes=1&events=0"><i
                 class="icon-file-text-alt"></i> <?php echo __('Thread + Internal Notes'); ?></a>
                 <li title="PDF File"><a class="no-pjax" target="_blank" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=print&notes=1&events=1"><i
                 class="icon-file-text-alt"></i> <?php echo __('Thread + Internal Notes + Events'); ?></a>
                 <?php if (extension_loaded('zip')) { ?>
                 <li title="ZIP Archive"><a class="no-pjax" target="_blank" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=zip&notes=1"><i
                 class="icon-folder-close-alt"></i> <?php echo __('Thread + Internal Notes + Attachments'); ?></a>
                 <li title="ZIP Archive"><a class="no-pjax" target="_blank" href="tickets.php?id=<?php echo $ticket->getId(); ?>&a=zip&notes=1&tasks=1"><i
                 class="icon-folder-close-alt"></i> <?php echo __('Thread + Internal Notes + Attachments + Tasks'); ?></a>
                 <?php } ?>
              </ul>
            </div>
            <?php
            // Transfer
            if ($role->hasPerm(Ticket::PERM_TRANSFER)) {?>
            <a class="action-button pull-right ticket-action" id="ticket-transfer" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Transfer'); ?>"
                data-redirect="tickets.php"
                href="#tickets/<?php echo $ticket->getId(); ?>/transfer"><i class="icon-share"></i></a>
            <?php
            } ?>

            <?php
            // Assign
            if ($ticket->isOpen() && $role->hasPerm(Ticket::PERM_ASSIGN)) {?>
            <span class="action-button pull-right"
                data-dropdown="#action-dropdown-assign"
                data-placement="bottom"
                data-toggle="tooltip"
                title=" <?php echo $ticket->isAssigned() ? __('Assign') : __('Reassign'); ?>"
                >
                <i class="icon-caret-down pull-right"></i>
                <a class="ticket-action" id="ticket-assign"
                    data-redirect="tickets.php"
                    href="#tickets/<?php echo $ticket->getId(); ?>/assign"><i class="icon-user"></i></a>
            </span>
            <div id="action-dropdown-assign" class="action-dropdown anchor-right">
              <ul>
                <?php
                // Agent can claim team assigned ticket
                if (!$ticket->getStaff()
                        && (!$dept->assignMembersOnly()
                            || $dept->isMember($thisstaff))
                        ) { ?>
                 <li><a class="no-pjax ticket-action"
                    data-redirect="tickets.php?id=<?php echo
                    $ticket->getId(); ?>"
                    href="#tickets/<?php echo $ticket->getId(); ?>/claim"><i
                    class="icon-chevron-sign-down"></i> <?php echo __('Claim'); ?></a>
                <?php
                } ?>
                 <li><a class="no-pjax ticket-action"
                    data-redirect="tickets.php"
                    href="#tickets/<?php echo $ticket->getId(); ?>/assign/agents"><i
                    class="icon-user"></i> <?php echo __('Agent'); ?></a>
                 <li><a class="no-pjax ticket-action"
                    data-redirect="tickets.php"
                    href="#tickets/<?php echo $ticket->getId(); ?>/assign/teams"><i
                    class="icon-group"></i> <?php echo __('Team'); ?></a>
              </ul>
            </div>
            <?php
            } ?>
            <div id="action-dropdown-more" class="action-dropdown anchor-right">
              <ul>
                <?php
                 if ($role->hasPerm(Ticket::PERM_EDIT)) { ?>
                    <li><a class="change-user" href="#tickets/<?php
                    echo $ticket->getId(); ?>/change-user"
                    onclick="javascript:
                        saveDraft();"
                    ><i class="icon-user"></i> <?php
                    echo __('Change Owner'); ?></a></li>
                <?php
                 }

                 if ($role->hasPerm(Ticket::PERM_MERGE) && !$ticket->isChild()) { ?>
                     <li><a href="#ajax.php/tickets/<?php echo $ticket->getId();
                         ?>/merge" onclick="javascript:
                         $.dialog($(this).attr('href').substr(1), 201);
                         return false"
                         ><i class="icon-code-fork"></i> <?php echo __('Merge Tickets'); ?></a></li>
                 <?php
                  }

                 if ($role->hasPerm(Ticket::PERM_LINK) && $ticket->getMergeType() == 'visual') { ?>
                     <li><a href="#ajax.php/tickets/<?php echo $ticket->getId();
                         ?>/link" onclick="javascript:
                         $.dialog($(this).attr('href').substr(1), 201);
                         return false"
                         ><i class="icon-link"></i> <?php echo __('Link Tickets'); ?></a></li>
                 <?php
                 }

                 if ($ticket->isAssigned() && $canRelease) { ?>
                        <li><a href="#tickets/<?php echo $ticket->getId();
                            ?>/release" class="ticket-action"
                             data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>" >
                               <i class="icon-unlock"></i> <?php echo __('Release (unassign) Ticket'); ?></a></li>
                 <?php
                 }
                 if($ticket->isOpen() && $isManager) {
                    if(!$ticket->isOverdue()) { ?>
                        <li><a class="confirm-action" id="ticket-overdue" href="#overdue"><i class="icon-bell"></i> <?php
                            echo __('Mark as Overdue'); ?></a></li>
                    <?php
                    }
                 }
                 if($ticket->isOpen() && $canMarkAnswered) {
                    if($ticket->isAnswered()) { ?>
                    <li><a href="#tickets/<?php echo $ticket->getId();
                        ?>/mark/unanswered" class="ticket-action"
                            data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>">
                            <i class="icon-circle-arrow-left"></i> <?php
                            echo __('Mark as Unanswered'); ?></a></li>
                    <?php
                    } else { ?>
                    <li><a href="#tickets/<?php echo $ticket->getId();
                        ?>/mark/answered" class="ticket-action"
                            data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>">
                            <i class="icon-circle-arrow-right"></i> <?php
                            echo __('Mark as Answered'); ?></a></li>
                    <?php
                    }
                } ?>

                <?php
                if ($role->hasPerm(Ticket::PERM_REFER)) { ?>
                <li><a href="#tickets/<?php echo $ticket->getId();
                    ?>/referrals" class="ticket-action"
                     data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>" >
                       <i class="icon-exchange"></i> <?php echo __('Manage Referrals'); ?></a></li>
                <?php
                } ?>
                <?php
                if ($role->hasPerm(Ticket::PERM_EDIT)) { ?>
                <li><a href="#ajax.php/tickets/<?php echo $ticket->getId();
                    ?>/forms/manage" onclick="javascript:
                    $.dialog($(this).attr('href').substr(1), 201);
                    return false"
                    ><i class="icon-paste"></i> <?php echo __('Manage Forms'); ?></a></li>
                <?php
                }

                if ($role->hasPerm(Ticket::PERM_REPLY) && $thread && $ticket->getId() == $thread->getObjectId()) {
                    ?>
                <li>

                    <?php
                    $recipients = __(' Manage Collaborators');

                    echo sprintf('<a class="collaborators manage-collaborators"
                            href="#thread/%d/collaborators/1"><i class="icon-group"></i>%s</a>',
                            $ticket->getThreadId(),
                            $recipients);
                   ?>
                </li>
                <?php
                } ?>


<?php           if ($thisstaff->hasPerm(Email::PERM_BANLIST)
                    && $role->hasPerm(Ticket::PERM_REPLY)) {
                     if(!$emailBanned) {?>
                        <li><a class="confirm-action" id="ticket-banemail"
                            href="#banemail"><i class="icon-ban-circle"></i> <?php echo sprintf(
                                Format::htmlchars(__('Ban Email <%s>')),
                                $ticket->getEmail()); ?></a></li>
                <?php
                     } elseif($unbannable) { ?>
                        <li><a  class="confirm-action" id="ticket-banemail"
                            href="#unbanemail"><i class="icon-undo"></i> <?php echo sprintf(
                                Format::htmlchars(__('Unban Email <%s>')),
                                $ticket->getEmail()); ?></a></li>
                    <?php
                     }
                  }
                  Signal::send('ticket.view.more', $ticket, $extras);
                  if ($role->hasPerm(Ticket::PERM_DELETE)) {
                     ?>
                    <li class="danger"><a class="ticket-action" href="#tickets/<?php
                    echo $ticket->getId(); ?>/status/delete"
                    data-redirect="tickets.php"><i class="icon-trash"></i> <?php
                    echo __('Delete Ticket'); ?></a></li>
                <?php
                 }
                ?>
              </ul>
            </div>
                <?php
                if (count($children) != 0)
                    echo sprintf('<span style="font-weight: 700; line-height: 26px;">%s</span>', __('PARENT'));
                elseif ($ticket->isChild())
                    echo sprintf('<span style="font-weight: 700; line-height: 26px;">%s</span>', __('CHILD'));
                if ($role->hasPerm(Ticket::PERM_REPLY)) { ?>
                <a href="#post-reply" class="post-response action-button"
                data-placement="bottom" data-toggle="tooltip"
                title="<?php echo __('Post Reply'); ?>"><i class="icon-mail-reply"></i></a>
                <?php
                } ?>
                <a href="#post-note" id="post-note" class="post-response action-button"
                data-placement="bottom" data-toggle="tooltip"
                title="<?php echo __('Post Internal Note'); ?>"><i class="icon-file-text"></i></a>
                <?php // Status change options
                echo TicketStatus::status_options();
                ?>
           </div>
        <div class="flush-left">
             <h2><a href="tickets.php?id=<?php echo $ticket->getId(); ?>"
             title="<?php echo __('Reload'); ?>"><i class="icon-refresh"></i>
             <?php echo sprintf(__('Ticket #%s'), $ticket->getNumber()); ?></a>
            </h2>
        </div>
    </div>
  </div>
</div>
<div class="clear tixTitle has_bottom_border">
    <h3>
    <?php $subject_field = TicketForm::getInstance()->getField('subject');
        echo $subject_field ? $subject_field->display($ticket->getSubject())
            : Format::htmlchars($ticket->getSubject()); ?>
    </h3>
</div>
<table class="ticket_info" cellspacing="0" cellpadding="0" width="940" border="0">
    <tr>
        <td width="50%">
            <table border="0" cellspacing="0" cellpadding="4" width="100%">
                <tr>
                    <th width="100"><?php echo __('Status');?>:</th>
                    <?php
                         if ($role->hasPerm(Ticket::PERM_CLOSE)) {?>
                         <td>
                          <a class="tickets-action" data-dropdown="#action-dropdown-statuses" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Change Status'); ?>"
                              data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>"
                              href="#statuses"
                              onclick="javascript:
                                  saveDraft();"
                              >
                              <?php echo $ticket->getStatus(); ?>
                          </a>
                        </td>
                      <?php } else { ?>
                          <td><?php echo ($S = $ticket->getStatus()) ? $S->display() : ''; ?></td>
                      <?php } ?>
                </tr>
                <tr>
                    <th><?php echo __('Priority');?>:</th>
                      <?php
                      if ($role->hasPerm(Ticket::PERM_EDIT)
                        && ($pf = $ticket->getPriorityField())) { ?>
                           <td>
                             <a class="inline-edit" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Update'); ?>"
                                 href="#tickets/<?php echo $ticket->getId();?>/field/<?php echo $pf->getId();?>/edit">
                                 <span id="field_<?php echo $pf->getId(); ?>"><?php echo $pf->getAnswer()->display(); ?></span>
                             </a>
                           </td>
                      <?php } else { ?>
                           <td><?php echo $ticket->getPriority(); ?></td>
                      <?php } ?>
                </tr>
                <tr>
                    <th><?php echo __('Department');?>:</th>
                    <?php
                    if ($role->hasPerm(Ticket::PERM_TRANSFER)) {?>
                      <td>
                          <a class="ticket-action" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Transfer'); ?>"
                            data-redirect="tickets.php?id=<?php echo $ticket->getId(); ?>"
                            href="#tickets/<?php echo $ticket->getId(); ?>/transfer"
                            onclick="javascript:
                                saveDraft();"
                            ><?php echo Format::htmlchars($ticket->getDeptName()); ?>
                        </a>
                      </td>
                    <?php
                  }else {?>
                    <td><?php echo Format::htmlchars($ticket->getDeptName()); ?></td>
                  <?php } ?>
                </tr>
                <tr>
                    <th><?php echo __('Create Date');?>:</th>
                    <td><?php echo Format::datetime($ticket->getCreateDate()); ?></td>
                </tr>
            </table>
        </td>
        <td width="50%" style="vertical-align:top">
            <table border="0" cellspacing="0" cellpadding="4" width="100%">
                <tr>
                    <th width="100"><?php echo __('User'); ?>:</th>
                    <td><a href="#tickets/<?php echo $ticket->getId(); ?>/user"
                        onclick="javascript:
                            saveDraft();
                            $.userLookup('ajax.php/tickets/<?php echo $ticket->getId(); ?>/user',
                                    function (user) {
                                        $('#user-'+user.id+'-name').text(user.name);
                                        $('#user-'+user.id+'-email').text(user.email);
                                        $('#user-'+user.id+'-phone').text(user.phone);
                                        $('select#emailreply option[value=1]').text(user.name+' <'+user.email+'>');
                                    });
                            return false;
                            "><i class="icon-user"></i> <span id="user-<?php echo $ticket->getOwnerId(); ?>-name"
                            ><?php echo Format::htmlchars($ticket->getName());
                        ?></span></a>
                        <?php
                        if ($user) { ?>
                            <a href="tickets.php?<?php echo Http::build_query(array(
                                'status'=>'open', 'a'=>'search', 'uid'=> $user->getId()
                            )); ?>" title="<?php echo __('Related Tickets'); ?>"
                            data-dropdown="#action-dropdown-stats">
                            (<b><?php echo $user->getNumTickets(); ?></b>)
                            </a>
                            <div id="action-dropdown-stats" class="action-dropdown anchor-right">
                                <ul>
                                    <?php
                                    if(($open=$user->getNumOpenTickets()))
                                        echo sprintf('<li><a href="tickets.php?a=search&status=open&uid=%s"><i class="icon-folder-open-alt icon-fixed-width"></i> %s</a></li>',
                                                $user->getId(), sprintf(_N('%d Open Ticket', '%d Open Tickets', $open), $open));

                                    if(($closed=$user->getNumClosedTickets()))
                                        echo sprintf('<li><a href="tickets.php?a=search&status=closed&uid=%d"><i
                                                class="icon-folder-close-alt icon-fixed-width"></i> %s</a></li>',
                                                $user->getId(), sprintf(_N('%d Closed Ticket', '%d Closed Tickets', $closed), $closed));
                                    ?>
                                    <li><a href="tickets.php?a=search&uid=<?php echo $ticket->getOwnerId(); ?>"><i class="icon-double-angle-right icon-fixed-width"></i> <?php echo __('All Tickets'); ?></a></li>
<?php   if ($thisstaff->hasPerm(User::PERM_DIRECTORY)) { ?>
                                    <li><a href="users.php?id=<?php echo
                                    $user->getId(); ?>"><i class="icon-user
                                    icon-fixed-width"></i> <?php echo __('Manage User'); ?></a></li>
<?php   } ?>
                                </ul>
                            </div>
                            <?php
                            if ($role->hasPerm(Ticket::PERM_EDIT) && $thread && $ticket->getId() == $thread->getObjectId()) {
                                if ($thread) {
                                    $numCollaborators = $thread->getNumCollaborators();
                                    if ($thread->getNumCollaborators())
                                        $recipients = sprintf(__('%d'),
                                                $numCollaborators);
                                } else
                                  $recipients = 0;

                             echo sprintf('<span><a class="manage-collaborators preview"
                                    href="#thread/%d/collaborators/1"><span id="t%d-recipients"><i class="icon-group"></i> (%s)</span></a></span>',
                                    $ticket->getThreadId(),
                                    $ticket->getThreadId(),
                                    $recipients);
                             }?>
<?php                   } # end if ($user) ?>
                    </td>
                </tr>
                <tr>
                    <th><?php echo __('Email'); ?>:</th>
                    <td>
                        <span id="user-<?php echo $ticket->getOwnerId(); ?>-email"><?php echo $ticket->getEmail(); ?></span>
                    </td>
                </tr>
<?php   if ($user->getOrganization()) { ?>
                <tr>
                    <th><?php echo __('Organization'); ?>:</th>
                    <td><i class="icon-building"></i>
                    <?php echo Format::htmlchars($user->getOrganization()->getName()); ?>
                        <a href="tickets.php?<?php echo Http::build_query(array(
                            'status'=>'open', 'a'=>'search', 'orgid'=> $user->getOrgId()
                        )); ?>" title="<?php echo __('Related Tickets'); ?>"
                        data-dropdown="#action-dropdown-org-stats">
                        (<b><?php echo $user->getNumOrganizationTickets(); ?></b>)
                        </a>
                            <div id="action-dropdown-org-stats" class="action-dropdown anchor-right">
                                <ul>
<?php   if ($open = $user->getNumOpenOrganizationTickets()) { ?>
                                    <li><a href="tickets.php?<?php echo Http::build_query(array(
                                        'a' => 'search', 'status' => 'open', 'orgid' => $user->getOrgId()
                                    )); ?>"><i class="icon-folder-open-alt icon-fixed-width"></i>
                                    <?php echo sprintf(_N('%d Open Ticket', '%d Open Tickets', $open), $open); ?>
                                    </a></li>
<?php   }
        if ($closed = $user->getNumClosedOrganizationTickets()) { ?>
                                    <li><a href="tickets.php?<?php echo Http::build_query(array(
                                        'a' => 'search', 'status' => 'closed', 'orgid' => $user->getOrgId()
                                    )); ?>"><i class="icon-folder-close-alt icon-fixed-width"></i>
                                    <?php echo sprintf(_N('%d Closed Ticket', '%d Closed Tickets', $closed), $closed); ?>
                                    </a></li>
                                    <li><a href="tickets.php?<?php echo Http::build_query(array(
                                        'a' => 'search', 'orgid' => $user->getOrgId()
                                    )); ?>"><i class="icon-double-angle-right icon-fixed-width"></i> <?php echo __('All Tickets'); ?></a></li>
<?php   }
        if ($thisstaff->hasPerm(User::PERM_DIRECTORY)) { ?>
                                    <li><a href="orgs.php?id=<?php echo $user->getOrgId(); ?>"><i
                                        class="icon-building icon-fixed-width"></i> <?php
                                        echo __('Manage Organization'); ?></a></li>
<?php   } ?>
                                </ul>
                            </div>
                        </td>
                    </tr>
<?php   } # end if (user->org) ?>
                <tr>
                  <th><?php echo __('Source'); ?>:</th>
                  <td>
                  <?php
                         if ($role->hasPerm(Ticket::PERM_EDIT)) {
                             $source = $ticket->getField('source');?>
                    <a class="inline-edit" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Update'); ?>"
                        href="#tickets/<?php echo $ticket->getId(); ?>/field/source/edit">
                        <span id="field_source">
                        <?php echo Format::htmlchars($ticket->getSource());
                        ?></span>
                    </a>
                      <?php
                         } else {
                            echo Format::htmlchars($ticket->getSource());
                        }

                    if (!strcasecmp($ticket->getSource(), 'Web') && $ticket->getIP())
                        echo '&nbsp;&nbsp; <span class="faded">('.Format::htmlchars($ticket->getIP()).')</span>';
                    ?>
                 </td>
                </tr>
            </table>
        </td>
    </tr>
</table>
<br>
<table class="ticket_info" cellspacing="0" cellpadding="0" width="940" border="0">
    <tr>
        <td width="50%">
            <table cellspacing="0" cellpadding="4" width="100%" border="0">
                <?php
                if($ticket->isOpen()) { ?>
                <tr>
                    <th width="100"><?php echo __('Assigned To');?>:</th>
                    <?php
                    if ($role->hasPerm(Ticket::PERM_ASSIGN)) {?>
                    <td>
                        <a class="inline-edit" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Update'); ?>"
                            href="#tickets/<?php echo $ticket->getId(); ?>/assign">
                            <span id="field_assign">
                                <?php if($ticket->isAssigned())
                                        echo Format::htmlchars(implode('/', $ticket->getAssignees()));
                                      else
                                        echo '<span class="faded">&mdash; '.__('Unassigned').' &mdash;</span>';
                        ?></span>
                        </a>
                    </td>
                    <?php
                    } else { ?>
                    <td>
                      <?php
                      if($ticket->isAssigned())
                          echo Format::htmlchars(implode('/', $ticket->getAssignees()));
                      else
                          echo '<span class="faded">&mdash; '.__('Unassigned').' &mdash;</span>';
                      ?>
                    </td>
                    <?php
                    } ?>
                </tr>
                <?php
                } else { ?>
                <tr>
                    <th width="100"><?php echo __('Closed By');?>:</th>
                    <td>
                        <?php
                        if(($staff = $ticket->getStaff()))
                            echo Format::htmlchars($staff->getName());
                        else
                            echo '<span class="faded">&mdash; '.__('Unknown').' &mdash;</span>';
                        ?>
                    </td>
                </tr>
                <?php
                } ?>
                <tr>
                    <th><?php echo __('SLA Plan');?>:</th>
                    <td>
                    <?php
                         if ($role->hasPerm(Ticket::PERM_EDIT)) {
                             $slaField = $ticket->getField('sla'); ?>
                          <a class="inline-edit" data-placement="bottom" data-toggle="tooltip" title="<?php echo __('Update'); ?>"
                          href="#tickets/<?php echo $ticket->getId(); ?>/field/sla/edit">
                          <span id="field_sla"><?php echo $sla ?: __('None'); ?></span>
                      </a>
                      <?php } else { ?>
                        <span id="field_sla"><?php echo $sla ?: __('None'); ?></span>
                      <?php } ?>
                    </td>
                </tr>
                <?php
                if($ticket->isOpen()){ ?>
                <tr>
                    <th><?php echo __('Due Date');?>:</th>
                    <?php
                         if ($role->hasPerm(Ticket::PERM_EDIT)) {
                             $duedate = $ticket->getField('duedate'); ?>
                           <td>
                      <a class="inline-edit" data-placement="bottom" data-toggle="tooltip"
                          title="<?php echo __('Update'); ?>"
                          href="#tickets/<?php echo $ticket->getId();
                           ?>/field/duedate/edit">
                           <?php $due_date = Format::datetime($ticket->getEstDueDate()); ?>
                           <span id="field_duedate" <?php if (!$due_date) echo 'class="faded"'; ?>>
                               <?php echo $due_date ?: '&mdash;'.__('Empty').'&mdash;'; ?>
                           </span>
                      </a>
                           </td>
                      <?php } else { ?>
                           <td><?php echo Format::datetime($ticket->getEstDueDate()); ?></td>
                      <?php } ?>
                </tr>
                <?php
                }else { ?>
                <tr>
                    <th><?php echo __('Close Date');?>:</th>
                    <td><?php echo Format::datetime($ticket->getCloseDate()); ?></td>
                </tr>
                <?php
                }
                ?>
            </table>
        </td>
        <td width="50%">
            <table cellspacing="0" cellpadding="4" width="100%" border="0">
                <tr>
                    <th width="100"><?php echo __('Help Topic');?>:</th>
                      <?php
                           if ($role->hasPerm(Ticket::PERM_EDIT)) {
                               $topic = $ticket->getField('topic'); ?>
                             <td>
                        <a class="inline-edit" data-placement="bottom"
                            data-toggle="tooltip" title="<?php echo __('Update'); ?>"
                            href="#tickets/<?php echo $ticket->getId(); ?>/field/topic/edit">
                            <span id="field_topic">
                                <?php echo $ticket->getHelpTopic() ?: __('None'); ?>
                            </span>
                        </a>
                      </td>
                        <?php } else { ?>
                             <td><?php echo Format::htmlchars($ticket->getHelpTopic()); ?></td>
                        <?php } ?>
                </tr>
                <tr>
                    <th nowrap><?php echo __('Last Message');?>:</th>
                    <td><?php echo Format::datetime($ticket->getLastMsgDate()); ?></td>
                </tr>
                <tr>
                    <th nowrap><?php echo __('Last Response');?>:</th>
                    <td><?php echo Format::datetime($ticket->getLastRespDate()); ?></td>
                </tr>
            </table>
        </td>
    </tr>
</table>
<br>
<?php
foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) {
    $form->addMissingFields();
    //Find fields to exclude if disabled by help topic
    $disabled = Ticket::getMissingRequiredFields($ticket, true);

    // Skip core fields shown earlier in the ticket view
    // TODO: Rewrite getAnswers() so that one could write
    //       ->getAnswers()->filter(not(array('field__name__in'=>
    //           array('email', ...))));
    $answers = $form->getAnswers()->exclude(Q::any(array(
        'field__flags__hasbit' => DynamicFormField::FLAG_EXT_STORED,
        'field__name__in' => array('subject', 'priority'),
        'field__id__in' => $disabled,
    )));
    $displayed = array();
    foreach($answers as $a) {
        if (!$a->getField()->isVisibleToStaff())
            continue;
        $displayed[] = $a;
    }
    if (count($displayed) == 0)
        continue;
    ?>
    <table class="ticket_info custom-data" cellspacing="0" cellpadding="0" width="940" border="0">
    <thead>
        <th colspan="2"><?php echo Format::htmlchars($form->getTitle()); ?></th>
    </thead>
    <tbody>
<?php
    foreach ($displayed as $a) {
        $id =  $a->getLocal('id');
        $label = $a->getLocal('label');
        $field = $a->getField();
        $config = $field->getConfiguration();
        $html = isset($config['html']) ? $config['html'] : false;
        $v = $html ? Format::striptags($a->display()) : $a->display();
        $class = (Format::striptags($v)) ? '' : 'class="faded"';
        $clean = (Format::striptags($v))
                ? ($html ? Format::striptags($v) : $v)
                : '&mdash;' . __('Empty') .  '&mdash;';
        $isFile = ($field instanceof FileUploadField);
        $url = "#tickets/".$ticket->getId()."/field/".$id;
?>
        <tr>
            <td width="200"><?php echo Format::htmlchars($label); ?>:</td>
            <td id="<?php echo sprintf('inline-answer-%s', $field->getId()); ?>">
            <?php if ($role->hasPerm(Ticket::PERM_EDIT)
                    && $field->isEditableToStaff()) {
                    $isEmpty = strpos($v, 'Empty') || ($v == '');
                    if ($isFile && !$isEmpty) {
                        echo sprintf('<span id="field_%s" %s >%s</span><br>', $id,
                            $class,
                            $clean);
                    }
                    $title = ($html && !$isEmpty) ? __('View Content') : __('Update');
                    $href = $url.(($html && !$isEmpty) ? '/view' : '/edit');
                         ?>
                  <a class="inline-edit" data-placement="bottom" data-toggle="tooltip" title="<?php echo $title; ?>"
                      href="<?php echo $href; ?>">
                  <?php
                    if ($isFile && !$isEmpty) {
                      echo "<i class=\"icon-edit\"></i>";
                    } elseif (strlen($v) > 200) {
                      $clean = Format::truncate($v, 200);
                      echo sprintf('<span id="field_%s" %s >%s</span>', $id, $class, $clean);
                      echo "<br><i class=\"icon-edit\"></i>";
                    } else
                        echo sprintf('<span id="field_%s" %s >%s</span>', $id, $class, $clean);

                    $a = $field->getAnswer();
                    $hint = ($field->isRequiredForClose() && $a && !$a->getValue() && get_class($field) != 'BooleanField') ?
                        sprintf('<i class="icon-warning-sign help-tip warning field-label" data-title="%s" data-content="%s"
                        /></i>', __('Required to close ticket'),
                        __('Data is required in this field in order to close the related ticket')) : '';
                    echo $hint;
                  ?>
              </a>
            <?php
            } else {
                echo $clean;
            } ?>
            </td>
        </tr>
<?php } ?>
    </tbody>
    </table>
<?php } ?>
<div class="clear"></div>

<?php
$tcount = $ticket->getThreadEntries($types) ? $ticket->getThreadEntries($types)->count() : 0;
?>
<ul  class="tabs clean threads" id="ticket_tabs" >
    <li class="active"><a id="ticket-thread-tab" href="#ticket_thread"><?php
        echo sprintf(__('Ticket Thread (%d)'), $tcount); ?></a></li>
    <li><a id="ticket-tasks-tab" href="#tasks"
            data-url="<?php
        echo sprintf('#tickets/%d/tasks', $ticket->getId()); ?>"><?php
        echo __('Tasks');
        if ($ticket->getNumTasks())
            echo sprintf('&nbsp;(<span id="ticket-tasks-count">%d</span>)', $ticket->getNumTasks());
        ?></a></li>
    <?php
    if ((count($children) != 0 || $ticket->isChild())) { ?>
    <li><a href="#relations" id="ticket-relations-tab"
        data-url="<?php
        echo sprintf('#tickets/%d/relations', $ticket->getId()); ?>"
        ><?php echo __('Related Tickets');
        if (count($children))
            echo sprintf('&nbsp;(<span id="ticket-relations-count">%d</span>)', count($children));
        elseif ($ticket->isChild())
            echo sprintf('&nbsp;(<span id="ticket-relations-count">%d</span>)', 1);
        ?></a></li>
    <?php
    }
    ?>

</ul>

<div id="ticket_tabs_container">
<div id="ticket_thread" class="tab_content">

<?php
    // Render ticket thread
    if ($thread)
        $thread->render(
                array('M', 'R', 'N'),
                array(
                    'html-id'   => 'ticketThread',
                    'mode'      => Thread::MODE_STAFF,
                    'sort'      => $thisstaff->thread_view_order
                    )
                );
?>
<div class="clear"></div>
<?php
if ($errors['err'] && isset($_POST['a'])) {
    // Reflect errors back to the tab.
    $errors[$_POST['a']] = $errors['err'];
} elseif($warn) { ?>
    <div id="msg_warning"><?php echo $warn; ?></div>
<?php
} ?>

<div class="sticky bar stop actions" id="response_options"
>
    <ul class="tabs" id="response-tabs">
        <?php
        if ($role->hasPerm(Ticket::PERM_REPLY) && !($blockReply)) { ?>
        <li class="active <?php
            echo isset($errors['reply']) ? 'error' : ''; ?>"><a
            href="#reply" id="post-reply-tab"><?php echo __('Post Reply');?></a></li>
        <?php
        }
        if (!($blockReply)) { ?>
        <li><a href="#note" <?php
            echo isset($errors['postnote']) ?  'class="error"' : ''; ?>
            id="post-note-tab"><?php echo __('Post Internal Note');?></a></li>
        <?php
        } ?>
    </ul>
    <?php
    if ($role->hasPerm(Ticket::PERM_REPLY) && !($blockReply)) {
        $replyTo = $_POST['reply-to'] ?: 'all';
        $emailReply = ($replyTo != 'none');
        ?>
    <form id="reply" class="tab_content spellcheck exclusive save"
        data-lock-object-id="ticket/<?php echo $ticket->getId(); ?>"
        data-lock-id="<?php echo $mylock ? $mylock->getId() : ''; ?>"
        action="tickets.php?id=<?php
        echo $ticket->getId(); ?>#reply" name="reply" method="post" enctype="multipart/form-data">
        <?php csrf_token(); ?>
        <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
        <input type="hidden" name="msgId" value="<?php echo $msgId; ?>">
        <input type="hidden" name="a" value="reply">
        <input type="hidden" name="lockCode" value="<?php echo $mylock ? $mylock->getCode() : ''; ?>">
        <table style="width:100%" border="0" cellspacing="0" cellpadding="3">
            <?php
            if ($errors['reply']) {?>
            <tr><td width="120">&nbsp;</td><td class="error"><?php echo $errors['reply']; ?>&nbsp;</td></tr>
            <?php
            }?>
           <tbody id="to_sec">
           <tr>
               <td width="120">
                   <label><strong><?php echo __('From'); ?>:</strong></label>
               </td>
               <td>
                   <select id="from_email_id" name="from_email_id">
                     <?php
                     // Department email (default).
                     if (($e=$dept->getEmail())) {
                        echo sprintf('<option value="%s" selected="selected">%s</option>',
                                 $e->getId(),
                                 Format::htmlchars($e->getAddress()));
                     }
                     $staffDepts = $thisstaff->getDepts();
                     if (in_array($cfg->getDefaultDeptId(), $staffDepts))
                         $staffDepts[] = 0;
                     // Optional SMTP addreses user can send email via
                     if (($emails = Email::getAddresses(array('smtp' => true,
                                 'depts' => $staffDepts), false)) && count($emails)) {
                         $emailId = $_POST['from_email_id'] ?: 0;
                         foreach ($emails as $e) {
                             if ($dept->getEmail()->getId() == $e->getId())
                                 continue;
                             echo sprintf('<option value="%s" %s>%s</option>',
                                     $e->getId(),
                                      $e->getId() == $emailId ?
                                      'selected="selected"' : '',
                                      Format::htmlchars($e->getAddress()));
                         }
                     }
                     ?>
                   </select>
               </td>
           </tr>
            </tbody>
            <tbody id="recipients">
             <tr id="user-row">
                <td width="120">
                    <label><strong><?php echo __('Recipients'); ?>:</strong></label>
                </td>
                <td><a href="#tickets/<?php echo $ticket->getId(); ?>/user"
                    onclick="javascript:
                        $.userLookup('ajax.php/tickets/<?php echo $ticket->getId(); ?>/user',
                                function (user) {
                                    window.location = 'tickets.php?id='<?php $ticket->getId(); ?>
                                });
                        return false;
                        "><span ><?php
                            echo Format::htmlchars($ticket->getOwner()->getEmail()->getAddress());
                    ?></span></a>
                </td>
              </tr>
               <tr><td>&nbsp;</td>
                   <td>
                   <div style="margin-bottom:2px;">
                    <?php
                    if ($ticket->getThread()->getNumCollaborators())
                        $recipients = sprintf(__('(%d of %d)'),
                                $ticket->getThread()->getNumActiveCollaborators(),
                                $ticket->getThread()->getNumCollaborators());

                         echo sprintf('<span"><a id="show_ccs">
                                 <i id="arrow-icon" class="icon-caret-right"></i>&nbsp;%s </a>
                                 &nbsp;
                                 <a class="manage-collaborators
                                 collaborators preview noclick %s"
                                  href="#thread/%d/collaborators/1">
                                 %s</a></span>',
                                 __('Collaborators'),
                                 $ticket->getNumCollaborators()
                                  ? '' : 'hidden',
                                 $ticket->getThreadId(),
                                         sprintf('<span id="t%d-recipients">%s</span></a></span>',
                                             $ticket->getThreadId(),
                                             $recipients)
                         );
                    ?>
                   </div>
                   <div id="ccs" class="hidden">
                     <div>
                        <span style="margin: 10px 5px 1px 0;" class="faded pull-left"><?php echo __('Select or Add New Collaborators'); ?>&nbsp;</span>
                        <?php
                        if ($role->hasPerm(Ticket::PERM_REPLY) && $thread && $ticket->getId() == $thread->getObjectId()) { ?>
                        <span class="action-button pull-left" style="margin: 2px  0 5px 20px;"
                            data-dropdown="#action-dropdown-collaborators"
                            data-placement="bottom"
                            data-toggle="tooltip"
                            title="<?php echo __('Manage Collaborators'); ?>"
                            >
                            <i class="icon-caret-down pull-right"></i>
                            <a class="ticket-action" id="collabs-button"
                                data-redirect="tickets.php?id=<?php echo
                                $ticket->getId(); ?>"
                                href="#thread/<?php echo
                                $ticket->getThreadId(); ?>/collaborators/1">
                                <i class="icon-group"></i></a>
                         </span>
                         <?php
                        }  ?>
                         <span class="error">&nbsp;&nbsp;<?php echo $errors['ccs']; ?></span>
                        </div>
                        <?php
                        if ($role->hasPerm(Ticket::PERM_REPLY) && $thread && $ticket->getId() == $thread->getObjectId()) { ?>
                        <div id="action-dropdown-collaborators" class="action-dropdown anchor-right">
                          <ul>
                             <li><a class="manage-collaborators"
                                href="#thread/<?php echo
                                $ticket->getThreadId(); ?>/add-collaborator/addcc"><i
                                class="icon-plus"></i> <?php echo __('Add New'); ?></a>
                             <li><a class="manage-collaborators"
                                href="#thread/<?php echo
                                $ticket->getThreadId(); ?>/collaborators/1"><i
                                class="icon-cog"></i> <?php echo __('Manage Collaborators'); ?></a>
                          </ul>
                        </div>
                        <?php
                        } ?>
                     <div class="clear">
                      <select id="collabselection" name="ccs[]" multiple="multiple"
                          data-placeholder="<?php
                            echo __('Select Active Collaborators'); ?>">
                          <?php
                          if ($collabs = $ticket->getCollaborators()) {
                              foreach ($collabs as $c) {
                                  echo sprintf('<option value="%s" %s class="%s">%s</option>',
                                          $c->getUserId(),
                                          $c->isActive() ?
                                          'selected="selected"' : '',
                                          $c->isActive() ?
                                          'active' : 'disabled',
                                          $c->getName());
                              }
                          }
                          ?>
                      </select>
                     </div>
                 </div>
                 </td>
             </tr>
             <tr>
                <td width="120">
                    <label><?php echo __('Reply To'); ?>:</label>
                </td>
                <td>
                    <?php
                    // Supported Reply Types
                    $replyTypes = array(
                            'all'   =>  __('All Active Recipients'),
                            'user'  =>  sprintf('%s (%s)',
                                __('Ticket Owner'),
                                Format::htmlchars($ticket->getOwner()->getEmail())),
                            'none'  =>  sprintf('&mdash; %s  &mdash;',
                                __('Do Not Email Reply'))
                            );

                    $replyTo = $_POST['reply-to'] ?: 'all';
                    $emailReply = ($replyTo != 'none');
                    ?>
                    <select id="reply-to" name="reply-to">
                        <?php
                        foreach ($replyTypes as $k => $v) {
                            echo sprintf('<option value="%s" %s>%s</option>',
                                    $k,
                                    ($k == $replyTo) ?
                                    'selected="selected"' : '',
                                    $v);
                        }
                        ?>
                    </select>
                    <i class="help-tip icon-question-sign" href="#reply_types"></i>
                </td>
             </tr>
            </tbody>
            <tbody id="resp_sec">
            <tr><td colspan="2">&nbsp;</td></tr>
            <tr>
                <td width="120" style="vertical-align:top">
                    <label><strong><?php echo __('Response');?>:</strong></label>
                </td>
                <td>
                <?php
                if ($errors['response'])
                    echo sprintf('<div class="error">%s</div>',
                            $errors['response']);

                if ($cfg->isCannedResponseEnabled()) { ?>
                  <div>
                    <select id="cannedResp" name="cannedResp">
                        <option value="0" selected="selected"><?php echo __('Select a canned response');?></option>
                        <option value='original'><?php echo __('Original Message'); ?></option>
                        <option value='lastmessage'><?php echo __('Last Message'); ?></option>
                        <?php
                        if(($cannedResponses=Canned::responsesByDeptId($ticket->getDeptId()))) {
                            echo '<option value="0" disabled="disabled">
                                ------------- '.__('Premade Replies').' ------------- </option>';
                            foreach($cannedResponses as $id =>$title)
                                echo sprintf('<option value="%d">%s</option>',$id,$title);
                        }
                        ?>
                    </select>
                    </div>
                    </td></tr>
                    <tr><td colspan="2">
                <?php } # endif (canned-resonse-enabled)
                    $signature = '';
                    switch ($thisstaff->getDefaultSignatureType()) {
                    case 'dept':
                        if ($dept && $dept->canAppendSignature())
                           $signature = $dept->getSignature();
                       break;
                    case 'mine':
                        $signature = $thisstaff->getSignature();
                        break;
                    } ?>
                    <input type="hidden" name="draft_id" value=""/>
                    <br/>
                    <textarea name="response" id="response" cols="50"
                        data-signature-field="signature" data-dept-id="<?php echo $dept->getId(); ?>"
                        data-signature="<?php
                            echo Format::htmlchars(Format::viewableImages($signature)); ?>"
                        placeholder="<?php echo __(
                        'Start writing your response here. Use canned responses from the drop-down above'
                        ); ?>"
                        rows="9" wrap="soft"
                        class="<?php if ($cfg->isRichTextEnabled()) echo 'richtext';
                            ?> draft draft-delete fullscreen" <?php
    list($draft, $attrs) = Draft::getDraftAndDataAttrs('ticket.response', $ticket->getId(), $info['response']);
    echo $attrs; ?>><?php echo ThreadEntryBody::clean($_POST ? $info['response'] : $draft);
                    ?></textarea>
                <div id="reply_form_attachments" class="attachments">
                <?php
                    print $response_form->getField('attachments')->render();
                ?>
                </div>
                </td>
            </tr>
            <tr>
                <td width="120">
                    <label for="signature" class="left"><?php echo __('Signature');?>:</label>
                </td>
                <td>
                    <?php
                    $info['signature']=$info['signature']?$info['signature']:$thisstaff->getDefaultSignatureType();
                    ?>
                    <label><input type="radio" name="signature" value="none" checked="checked"> <?php echo __('None');?></label>
                    <?php
                    if($thisstaff->getSignature()) {?>
                    <label><input type="radio" name="signature" value="mine"
                        <?php echo ($info['signature']=='mine')?'checked="checked"':''; ?>> <?php echo __('My Signature');?></label>
                    <?php
                    } ?>
                    <?php
                    if($dept && $dept->canAppendSignature()) { ?>
                    <label><input type="radio" name="signature" value="dept"
                        <?php echo ($info['signature']=='dept')?'checked="checked"':''; ?>>
                        <?php echo sprintf(__('Department Signature (%s)'), Format::htmlchars($dept->getName())); ?></label>
                    <?php
                    } ?>
                </td>
            </tr>
            <tr>
                <td width="120" style="vertical-align:top">
                    <label><strong><?php echo __('Ticket Status');?>:</strong></label>
                </td>
                <td>
                    <?php
                    $outstanding = false;
                    if ($role->hasPerm(Ticket::PERM_CLOSE)
                            && is_string($warning=$ticket->isCloseable())) {
                        $outstanding =  true;
                        echo sprintf('<div class="warning-banner">%s</div>', $warning);
                    } ?>
                    <select name="reply_status_id">
                    <?php
                    $statusId = $info['reply_status_id'] ?: $ticket->getStatusId();
                    $states = array('open');
                    if ($role->hasPerm(Ticket::PERM_CLOSE) && !$outstanding)
                        $states = array_merge($states, array('closed'));

                    foreach (TicketStatusList::getStatuses(
                                array('states' => $states)) as $s) {
                        if (!$s->isEnabled()) continue;
                        $selected = ($statusId == $s->getId());
                        echo sprintf('<option value="%d" %s>%s%s</option>',
                                $s->getId(),
                                $selected
                                 ? 'selected="selected"' : '',
                                __($s->getName()),
                                $selected
                                ? (' ('.__('current').')') : ''
                                );
                    }
                    ?>
                    </select>
                </td>
            </tr>
         </tbody>
        </table>
        <p  style="text-align:center;">
            <input class="save pending" type="submit" value="<?php echo __('Post Reply');?>">
            <input class="" type="reset" value="<?php echo __('Reset');?>">
        </p>
    </form>
    <?php
    }
    if (!($blockReply)) {
    ?>
    <form id="note" class="hidden tab_content spellcheck exclusive save"
        data-lock-object-id="ticket/<?php echo $ticket->getId(); ?>"
        data-lock-id="<?php echo $mylock ? $mylock->getId() : ''; ?>"
        action="tickets.php?id=<?php echo $ticket->getId(); ?>#note"
        name="note" method="post" enctype="multipart/form-data">
        <?php csrf_token(); ?>
        <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
        <input type="hidden" name="locktime" value="<?php echo $cfg->getLockTime() * 60; ?>">
        <input type="hidden" name="a" value="postnote">
        <input type="hidden" name="lockCode" value="<?php echo $mylock ? $mylock->getCode() : ''; ?>">
        <table width="100%" border="0" cellspacing="0" cellpadding="3">
            <?php
            if($errors['postnote']) {?>
            <tr>
                <td width="120">&nbsp;</td>
                <td class="error"><?php echo $errors['postnote']; ?></td>
            </tr>
            <?php
            } ?>
            <tr>
                <td width="120" style="vertical-align:top">
                    <label><strong><?php echo __('Internal Note'); ?>:</strong><span class='error'>&nbsp;*</span></label>
                </td>
                <td>
                    <div>
                        <div class="faded" style="padding-left:0.15em"><?php
                        echo __('Note title - summary of the note (optional)'); ?></div>
                        <input type="text" name="title" id="title" size="60" value="<?php echo $info['title']; ?>" >
                        <br/>
                        <span class="error">&nbsp;<?php echo $errors['title']; ?></span>
                    </div>
                </td></tr>
                <tr><td colspan="2">
                    <div class="error"><?php echo $errors['note']; ?></div>
                    <textarea name="note" id="internal_note" cols="80"
                        placeholder="<?php echo __('Note details'); ?>"
                        rows="9" wrap="soft"
                        class="<?php if ($cfg->isRichTextEnabled()) echo 'richtext';
                            ?> draft draft-delete fullscreen" <?php
    list($draft, $attrs) = Draft::getDraftAndDataAttrs('ticket.note', $ticket->getId(), $info['note']);
    echo $attrs; ?>><?php echo ThreadEntryBody::clean($_POST ? $info['note'] : $draft);
                        ?></textarea>
                <div class="attachments">
                <?php
                    print $note_form->getField('attachments')->render();
                ?>
                </div>
                </td>
            </tr>
            <tr><td colspan="2">&nbsp;</td></tr>
            <tr>
                <td width="120">
                    <label><?php echo __('Ticket Status');?>:</label>
                </td>
                <td>
                    <div class="faded"></div>
                    <select name="note_status_id">
                        <?php
                        $statusId = $info['note_status_id'] ?: $ticket->getStatusId();
                        $states = array('open');
                        if ($ticket->isCloseable() === true
                                && $role->hasPerm(Ticket::PERM_CLOSE))
                            $states = array_merge($states, array('closed'));
                        foreach (TicketStatusList::getStatuses(
                                    array('states' => $states)) as $s) {
                            if (!$s->isEnabled()) continue;
                            $selected = $statusId == $s->getId();
                            echo sprintf('<option value="%d" %s>%s%s</option>',
                                    $s->getId(),
                                    $selected ? 'selected="selected"' : '',
                                    __($s->getName()),
                                    $selected ? (' ('.__('current').')') : ''
                                    );
                        }
                        ?>
                    </select>
                    &nbsp;<span class='error'>*&nbsp;<?php echo $errors['note_status_id']; ?></span>
                </td>
            </tr>
        </table>

       <p style="text-align:center;">
           <input class="save pending" type="submit" value="<?php echo __('Post Note');?>">
           <input class="" type="reset" value="<?php echo __('Reset');?>">
       </p>
   </form>
   <?php } ?>
 </div>
 </div>
</div>
<div style="display:none;" class="dialog" id="print-options">
    <h3><?php echo __('Ticket Print Options');?></h3>
    <a class="close" href=""><i class="icon-remove-circle"></i></a>
    <hr/>
    <form action="tickets.php?id=<?php echo $ticket->getId(); ?>"
        method="post" id="print-form" name="print-form" target="_blank">
        <?php csrf_token(); ?>
        <input type="hidden" name="a" value="print">
        <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
        <fieldset class="notes">
            <label class="fixed-size" for="notes"><?php echo __('Print Notes');?>:</label>
            <label class="inline checkbox">
            <input type="checkbox" id="notes" name="notes" value="1"> <?php echo __('Print <b>Internal</b> Notes/Comments');?>
            </label>
        </fieldset>
        <fieldset class="events">
            <label class="fixed-size" for="events"><?php echo __('Print Events');?>:</label>
            <label class="inline checkbox">
            <input type="checkbox" id="events" name="events" value="1"> <?php echo __('Print Thread Events');?>
            </label>
        </fieldset>
        <fieldset>
            <label class="fixed-size" for="psize"><?php echo __('Paper Size');?>:</label>
            <select id="psize" name="psize">
                <option value="">&mdash; <?php echo __('Select Print Paper Size');?> &mdash;</option>
                <?php
                  $psize =$_SESSION['PAPER_SIZE']?$_SESSION['PAPER_SIZE']:$thisstaff->getDefaultPaperSize();
                  foreach(Export::$paper_sizes as $v) {
                      echo sprintf('<option value="%s" %s>%s</option>',
                                $v,($psize==$v)?'selected="selected"':'', __($v));
                  }
                ?>
            </select>
        </fieldset>
        <hr style="margin-top:3em"/>
        <p class="full-width">
            <span class="buttons pull-left">
                <input type="reset" value="<?php echo __('Reset');?>">
                <input type="button" value="<?php echo __('Cancel');?>" class="close">
            </span>
            <span class="buttons pull-right">
                <input type="submit" value="<?php echo __('Print');?>">
            </span>
         </p>
    </form>
    <div class="clear"></div>
</div>
<div style="display:none;" class="dialog" id="confirm-action">
    <h3><?php echo __('Please Confirm');?></h3>
    <a class="close" href=""><i class="icon-remove-circle"></i></a>
    <hr/>
    <p class="confirm-action" style="display:none;" id="claim-confirm">
        <?php echo sprintf(__('Are you sure you want to <b>claim</b> (self assign) %s?'), __('this ticket'));?>
    </p>
    <p class="confirm-action" style="display:none;" id="answered-confirm">
        <?php echo __('Are you sure you want to flag the ticket as <b>answered</b>?');?>
    </p>
    <p class="confirm-action" style="display:none;" id="unanswered-confirm">
        <?php echo __('Are you sure you want to flag the ticket as <b>unanswered</b>?');?>
    </p>
    <p class="confirm-action" style="display:none;" id="overdue-confirm">
        <?php echo __('Are you sure you want to flag the ticket as <font color="red"><b>overdue</b></font>?');?>
    </p>
    <p class="confirm-action" style="display:none;" id="banemail-confirm">
        <?php echo sprintf(__('Are you sure you want to <b>ban</b> %s?'), $ticket->getEmail());?> <br><br>
        <?php echo __('New tickets from the email address will be automatically rejected.');?>
    </p>
    <p class="confirm-action" style="display:none;" id="unbanemail-confirm">
        <?php echo sprintf(__('Are you sure you want to <b>remove</b> %s from ban list?'), $ticket->getEmail()); ?>
    </p>
    <p class="confirm-action" style="display:none;" id="release-confirm">
        <?php echo sprintf(__('Are you sure you want to <b>unassign</b> ticket from <b>%s</b>?'), $ticket->getAssigned()); ?>
    </p>
    <p class="confirm-action" style="display:none;" id="changeuser-confirm">
        <span id="msg_warning" style="display:block;vertical-align:top">
        <?php echo sprintf(Format::htmlchars(__('%s <%s> will no longer have access to the ticket')),
            '<b>'.Format::htmlchars($ticket->getName()).'</b>', Format::htmlchars($ticket->getEmail())); ?>
        </span>
        <?php echo sprintf(__('Are you sure you want to <b>change</b> ticket owner to %s?'),
            '<b><span id="newuser">this guy</span></b>'); ?>
    </p>
    <p class="confirm-action" style="display:none;" id="delete-confirm">
        <font color="red"><strong><?php echo sprintf(
            __('Are you sure you want to DELETE %s?'), __('this ticket'));?></strong></font>
        <br><br><?php echo __('Deleted data CANNOT be recovered, including any associated attachments.');?>
    </p>
    <div><?php echo __('Please confirm to continue.');?></div>
    <form action="tickets.php?id=<?php echo $ticket->getId(); ?>" method="post" id="confirm-form" name="confirm-form">
        <?php csrf_token(); ?>
        <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
        <input type="hidden" name="a" value="process">
        <input type="hidden" name="do" id="action" value="">
        <hr style="margin-top:1em"/>
        <p class="full-width">
            <span class="buttons pull-left">
                <input type="button" value="<?php echo __('Cancel');?>" class="close">
            </span>
            <span class="buttons pull-right">
                <input type="submit" value="<?php echo __('OK');?>">
            </span>
         </p>
    </form>
    <div class="clear"></div>
</div>
<script type="text/javascript">
$(function() {
    $(document).on('click', 'a.change-user', function(e) {
        e.preventDefault();
        var tid = <?php echo $ticket->getOwnerId(); ?>;
        var cid = <?php echo $ticket->getOwnerId(); ?>;
        var url = 'ajax.php/'+$(this).attr('href').substr(1);
        $.userLookup(url, function(user) {
            if(cid!=user.id
                    && $('.dialog#confirm-action #changeuser-confirm').length) {
                $('#newuser').html(user.name +' &lt;'+user.email+'&gt;');
                $('.dialog#confirm-action #action').val('changeuser');
                $('#confirm-form').append('<input type=hidden name=user_id value='+user.id+' />');
                $('#overlay').show();
                $('.dialog#confirm-action .confirm-action').hide();
                $('.dialog#confirm-action p#changeuser-confirm')
                .show()
                .parent('div').show().trigger('click');
            }
        });
    });

    $(document).on('click', 'a.manage-collaborators', function(e) {
        e.preventDefault();
        var url = 'ajax.php/'+$(this).attr('href').substr(1);
        $.dialog(url, 201, function (xhr) {
           var resp = $.parseJSON(xhr.responseText);
           if (resp.user && !resp.users)
              resp.users.push(resp.user);
            // TODO: Process resp.users
           $('.tip_box').remove();
        }, {
            onshow: function() { $('#user-search').focus(); }
        });
        return false;
     });

    // Post Reply or Note action buttons.
    $('a.post-response').click(function (e) {
        var $r = $('ul.tabs > li > a'+$(this).attr('href')+'-tab');
        if ($r.length) {
            // Make sure ticket thread tab is visiable.
            var $t = $('ul#ticket_tabs > li > a#ticket-thread-tab');
            if ($t.length && !$t.hasClass('active'))
                $t.trigger('click');
            // Make the target response tab active.
            if (!$r.hasClass('active'))
                $r.trigger('click');

            // Scroll to the response section.
            var $stop = $(document).height();
            var $s = $('div#response_options');
            if ($s.length)
                $stop = $s.offset().top-125

            $('html, body').animate({scrollTop: $stop}, 'fast');
        }

        return false;
    });

  $('#show_ccs').click(function() {
    var show = $('#arrow-icon');
    var collabs = $('a#managecollabs');
    $('#ccs').slideToggle('fast', function(){
        if ($(this).is(":hidden")) {
            collabs.hide();
            show.removeClass('icon-caret-down').addClass('icon-caret-right');
        } else {
            collabs.show();
            show.removeClass('icon-caret-right').addClass('icon-caret-down');
        }
    });
    return false;
   });

  $('.collaborators.noclick').click(function() {
    $('#show_ccs').trigger('click');
   });

  $('#collabselection').select2({
    width: '350px',
    allowClear: true,
    sorter: function(data) {
        return data.filter(function (item) {
                return !item.selected;
                });
    },
    templateResult: function(e) {
        var $e = $(
        '<span><i class="icon-user"></i> ' + e.text + '</span>'
        );
        return $e;
    }
   }).on("select2:unselecting", function(e) {
        if (!confirm(__("Are you sure you want to DISABLE the collaborator?")))
            e.preventDefault();
   }).on("select2:selecting", function(e) {
        if (!confirm(__("Are you sure you want to ENABLE the collaborator?")))
             e.preventDefault();
   }).on('change', function(e) {
    var id = e.currentTarget.id;
    var count = $('li.select2-selection__choice').length;
    var total = $('#' + id +' option').length;
    $('.' + id + '__count').html(count);
    $('.' + id + '__total').html(total);
    $('.' + id + '__total').parent().toggle((total));
   }).on('select2:opening select2:closing', function(e) {
    $(this).parent().find('.select2-search__field').prop('disabled', true);
   });
});
function saveDraft() {
    redactor = $('#response').redactor('plugin.draft');
    if (redactor.opts.draftId)
        $('#response').redactor('plugin.draft.saveDraft');
}
</script>

queues-ticket.inc.php:
    <div>
        <div class="pull-right">
            <a href="queues.php?t=tickets&amp;a=add" class="green button action-button"><i class="icon-plus-sign"></i> <?php echo __('Add New Queue');?></a>
            <span class="action-button" data-dropdown="#action-dropdown-more">
                        <i class="icon-caret-down pull-right"></i>
                        <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
            </span>
            <div id="action-dropdown-more" class="action-dropdown anchor-right">
                <ul id="actions">
                    <li>
                        <a class="queue-action no-pjax" data-action="enable" href="#queues.php">
                            <i class="icon-ok-sign icon-fixed-width"></i>
                            <?php echo __( 'Enable'); ?>
                        </a>
                    </li>
                    <li>
                        <a class="queue-action no-pjax" data-action="disable" href="#queues.php">
                            <i class="icon-ban-circle icon-fixed-width"></i>
                            <?php echo __( 'Disable'); ?>
                        </a>
                    </li>
                    <li class="danger">
                        <a class="queue-action no-pjax" data-action="delete" href="#queues.php">
                            <i class="icon-trash icon-fixed-width"></i>
                            <?php echo __( 'Delete'); ?>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
        <input type="hidden" name="do" value="mass_process" />
        <h3><?php echo __('Ticket Queues');?></h3>
    </div>
    <div class="clear"></div>
 <?php csrf_token(); ?>
 <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
    <thead>
        <tr>
            <th width="3%">&nbsp;</th>
            <th colspan="5" width="47%"><?php echo __('Name');?></th>
            <th width="12%"><?php echo __('Creator');?></th>
            <th width="8%"><?php echo __('Status');?></th>
            <th width="10%" nowrap><?php echo __('Created');?></th>
        </tr>
    </thead>
    <tbody class="sortable-rows" data-sort="qsort">
<?php
$all_queues = CustomQueue::queues()->getIterator();
$emitLevel = function($queues, $level=0) use ($all_queues, &$emitLevel) {
    $queues->sort(function($a) { return $a->sort; });
    foreach ($queues as $q) { ?>
      <tr>
<?php if ($level) { ?>
        <td colspan="<?php echo max(1, $level); ?>"></td>
<?php } ?>
        <td>
          <input type="checkbox" class="mass checkbox"  name="qids[]" value="<?php echo $q->id; ?>" />
          <input type="hidden" name="qsort[<?php echo $q->id; ?>]"
            value="<?php echo $q->sort; ?>"/>
        </td>
        <td width="63%" colspan="<?php echo max(1, 5-$level); ?>"><a
          href="queues.php?id=<?php echo $q->getId(); ?>"><?php
          echo Format::htmlchars($q->getFullName()); ?></a>
          <i class="faded-more pull-right icon-sort"></i></td>
        <td><?php echo Format::htmlchars($q->staff ? $q->staff->getName() :
        __('SYSTEM')); ?></td>
        <td><?php echo Format::htmlchars($q->getStatus()); ?></td>
        <td><?php echo Format::date($q->created); ?></td>
      </tr>
<?php
        $children = $all_queues->findAll(array('parent_id' => $q->id));
        if (count($children)) {
            $emitLevel($children, $level+1);
        }
    }
};

$emitLevel($all_queues->findAll(array('parent_id' => 0)));
?>
    </tbody>
</table>

<script>
$(function() {
  var goBaby = function(action) {
    var ids = [], that = this,
        $form = $(this).closest('form');
    $('input:checkbox.mass:checked', $form).each(function() {
      ids.push($(this).val());
    });
    if (ids.length) {
      $.confirm(__('You sure?')).then(function(promise) {
        if (promise === false)
          return false;
        $.each(ids, function() { $form.append($('<input type="hidden" name="ids[]">').val(this)); });
        $form.append($('<input type="hidden" name="a" />')
          .val($(that).data('action')));
        $form.append($('<input type="hidden" name="count" />')
          .val(ids.length));
        $form.attr('action', action);
        // I don't know why, but submitting the form doesn't work...
        $form.find('[type=submit]').trigger('click');
      });
    }
    else {
      $.sysAlert(__('Oops'),
        __('You need to select at least one item'));
    }
  };
  $(document).on('click', 'a.queue-action', function(e) {
    e.preventDefault();
    goBaby.call(this, $(this).attr('href').substr(1));
    return false;
  });
});
</script>
staff/ticket-open.inc.php:
<?php
if (!defined('OSTSCPINC') || !$thisstaff
        || !$thisstaff->hasPerm(Ticket::PERM_CREATE, false))
        die('Access Denied');

$info=array();
$info=Format::htmlchars(($errors && $_POST)?$_POST:$info, true);

if ($_SESSION[':form-data'] && !$_GET['tid'])
  unset($_SESSION[':form-data']);

//  Use thread entry to seed the ticket
if (!$user && $_GET['tid'] && ($entry = ThreadEntry::lookup($_GET['tid']))) {
    if ($entry->getThread()->getObjectType() == 'T')
      $oldTicketId = $entry->getThread()->getObjectId();
    if ($entry->getThread()->getObjectType() == 'A')
      $oldTaskId = $entry->getThread()->getObjectId();

    $_SESSION[':form-data']['message'] = Format::htmlchars($entry->getBody());
    $_SESSION[':form-data']['ticketId'] = $oldTicketId;
    $_SESSION[':form-data']['taskId'] = $oldTaskId;
    $_SESSION[':form-data']['eid'] = $entry->getId();
    $_SESSION[':form-data']['timestamp'] = $entry->getCreateDate();

    if ($entry->user_id)
       $user = User::lookup($entry->user_id);

     if (($m= TicketForm::getInstance()->getField('message'))) {
         $k = 'attach:'.$m->getId();
         unset($_SESSION[':form-data'][$k]);
        foreach ($entry->getAttachments() as $a) {
          if (!$a->inline && $a->file) {
            $_SESSION[':form-data'][$k][$a->file->getId()] = $a->getFilename();
            $_SESSION[':uploadedFiles'][$a->file->getId()] = $a->getFilename();
          }
        }
     }
}

if (!$info['topicId'])
    $info['topicId'] = $cfg->getDefaultTopicId();

$forms = array();
if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) {
    foreach ($topic->getForms() as $F) {
        if (!$F->hasAnyVisibleFields())
            continue;
        if ($_POST) {
            $F = $F->instanciate();
            $F->isValidForClient();
        }
        $forms[] = $F;
    }
}

if ($_POST)
    $info['duedate'] = Format::date(strtotime($info['duedate']), false, false, 'UTC');
?>
<form action="tickets.php?a=open" method="post" class="save"  enctype="multipart/form-data">
 <?php csrf_token(); ?>
 <input type="hidden" name="do" value="create">
 <input type="hidden" name="a" value="open">
<div style="margin-bottom:20px; padding-top:5px;">
    <div class="pull-left flush-left">
        <h2><?php echo __('Open a New Ticket');?></h2>
    </div>
</div>
 <table class="form_table fixed" width="940" border="0" cellspacing="0" cellpadding="2">
    <thead>
    <!-- This looks empty - but beware, with fixed table layout, the user
         agent will usually only consult the cells in the first row to
         construct the column widths of the entire toable. Therefore, the
         first row needs to have two cells -->
        <tr><td style="padding:0;"></td><td style="padding:0;"></td></tr>
    </thead>
    <tbody>
        <tr>
            <th colspan="2">
                <em><strong><?php echo __('User and Collaborators'); ?></strong>: </em>
                <div class="error"><?php echo $errors['user']; ?></div>
            </th>
        </tr>
              <?php
              if ($user) { ?>
                  <tr><td><?php echo __('User'); ?>:</td><td>
                    <div id="user-info">
                      <input type="hidden" name="uid" id="uid" value="<?php echo $user->getId(); ?>" />
                      <?php if ($thisstaff->hasPerm(User::PERM_EDIT)) { ?>
                      <a href="#" onclick="javascript:
                      $.userLookup('ajax.php/users/<?php echo $user->getId(); ?>/edit',
                      function (user) {
                        $('#user-name').text(user.name);
                        $('#user-email').text(user.email);
                      });
                      return false;
                      ">
                      <?php } else { ?>
                      <a href="#">
                      <?php } ?>
                      <i class="icon-user"></i>
                      <span id="user-name"><?php echo Format::htmlchars($user->getName()); ?></span>
                      &lt;<span id="user-email"><?php echo $user->getEmail(); ?></span>&gt;
                    </a>
                    <a class="inline button" style="overflow:inherit" href="#"
                    onclick="javascript:
                    $.userLookup('ajax.php/users/select/'+$('input#uid').val(),
                    function(user) {
                      $('input#uid').val(user.id);
                      $('#user-name').text(user.name);
                      $('#user-email').text('<'+user.email+'>');
                    });
                    return false;
                    "><i class="icon-retweet"></i> <?php echo __('Change'); ?></a>
                  </div>
                </td>
              </tr>
              <?php
            } else { //Fallback: Just ask for email and name
              ?>
              <tr id="userRow">
                <td width="120"><?php echo __('User'); ?>:</td>
                <td>
                  <span>
                    <select class="userSelection" name="name" id="user-name"
                    data-placeholder="<?php echo __('Select User'); ?>">
                  </select>
                </span>

                <a class="inline button" style="overflow:inherit" href="#"
                onclick="javascript:
                $.userLookup('ajax.php/users/lookup/form', function (user) {
                  var newUser = new Option(user.email + ' - ' + user.name, user.id, true, true);
                  return $(&quot;#user-name&quot;).append(newUser).trigger('change');
                });
                return false;
                "><i class="icon-plus"></i> <?php echo __('Add New'); ?></a>

                <span class="error">*</span>
                <br/><span class="error"><?php echo $errors['name']; ?></span>
              </td>
              <div>
                <input type="hidden" size=45 name="email" id="user-email" class="attached"
                placeholder="<?php echo __('User Email'); ?>"
                autocomplete="off" autocorrect="off" value="<?php echo $info['email']; ?>" />
              </div>
            </tr>
            <?php
          } ?>
          <tr id="ccRow">
            <td width="160"><?php echo __('Cc'); ?>:</td>
            <td>
              <span>
                <select class="collabSelections" name="ccs[]" id="cc_users_open" multiple="multiple"
                ref="tags" data-placeholder="<?php echo __('Select Contacts'); ?>">
              </select>
            </span>

            <a class="inline button" style="overflow:inherit" href="#"
            onclick="javascript:
            $.userLookup('ajax.php/users/lookup/form', function (user) {
              var newUser = new Option(user.name, user.id, true, true);
              return $(&quot;#cc_users_open&quot;).append(newUser).trigger('change');
            });
            return false;
            "><i class="icon-plus"></i> <?php echo __('Add New'); ?></a>

            <br/><span class="error"><?php echo $errors['ccs']; ?></span>
          </td>
        </tr>
        <?php
        if ($cfg->notifyONNewStaffTicket()) {
         ?>
        <tr class="no_border">
          <td>
            <?php echo __('Ticket Notice');?>:
          </td>
          <td>
            <select id="reply-to" name="reply-to">
              <option value="all"><?php echo __('Alert All'); ?></option>
              <option value="user"><?php echo __('Alert to User'); ?></option>
              <option value="none">&mdash; <?php echo __('Do Not Send Alert'); ?> &mdash;</option>
            </select>
          </td>
        </tr>
      <?php } ?>
    </tbody>
    <tbody>
        <tr>
            <th colspan="2">
                <em><strong><?php echo __('Ticket Information and Options');?></strong>:</em>
            </th>
        </tr>
        <tr>
            <td width="160" class="required">
                <?php echo __('Ticket Source');?>:
            </td>
            <td>
                <select name="source">
                    <?php
                    $source = $info['source'] ?: 'Phone';
                    $sources = Ticket::getSources();
                    unset($sources['Web'], $sources['API']);
                    foreach ($sources as $k => $v)
                        echo sprintf('<option value="%s" %s>%s</option>',
                                $k,
                                ($source == $k ) ? 'selected="selected"' : '',
                                $v);
                    ?>
                </select>
                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['source']; ?></font>
            </td>
        </tr>
        <tr>
            <td width="160" class="required">
                <?php echo __('Help Topic'); ?>:
            </td>
            <td>
                <select name="topicId" onchange="javascript:
                        var data = $(':input[name]', '#dynamic-form').serialize();
                        $.ajax(
                          'ajax.php/form/help-topic/' + this.value,
                          {
                            data: data,
                            dataType: 'json',
                            success: function(json) {
                              $('#dynamic-form').empty().append(json.html);
                              $(document.head).append(json.media);
                            }
                          });">
                    <?php
                    if ($topics=$thisstaff->getTopicNames(false, false)) {
                        if (count($topics) == 1)
                            $selected = 'selected="selected"';
                        else { ?>
                        <option value="" selected >&mdash; <?php echo __('Select Help Topic'); ?> &mdash;</option>
<?php                   }
                        foreach($topics as $id =>$name) {
                            echo sprintf('<option value="%d" %s %s>%s</option>',
                                $id, ($info['topicId']==$id)?'selected="selected"':'',
                                $selected, $name);
                        }
                        if (count($topics) == 1 && !$forms) {
                            if (($T = Topic::lookup($id)))
                                $forms =  $T->getForms();
                        }
                    }
                    ?>
                </select>
                &nbsp;<font class="error"><b>*</b>&nbsp;<?php echo $errors['topicId']; ?></font>
            </td>
        </tr>
        <tr>
            <td width="160">
                <?php echo __('Department'); ?>:
            </td>
            <td>
                <select name="deptId">
                    <option value="" selected >&mdash; <?php echo __('Select Department'); ?>&mdash;</option>
                    <?php
                    if($depts=$thisstaff->getDepartmentNames(true)) {
                        foreach($depts as $id =>$name) {
                            if (!($role = $thisstaff->getRole($id))
                                || !$role->hasPerm(Ticket::PERM_CREATE)
                            ) {
                                // No access to create tickets in this dept
                                continue;
                            }
                            echo sprintf('<option value="%d" %s>%s</option>',
                                    $id, ($info['deptId']==$id)?'selected="selected"':'',$name);
                        }
                    }
                    ?>
                </select>
                &nbsp;<font class="error"><?php echo $errors['deptId']; ?></font>
            </td>
        </tr>

         <tr>
            <td width="160">
                <?php echo __('SLA Plan');?>:
            </td>
            <td>
                <select name="slaId">
                    <option value="0" selected="selected" >&mdash; <?php echo __('System Default');?> &mdash;</option>
                    <?php
                    if($slas=SLA::getSLAs()) {
                        foreach($slas as $id =>$name) {
                            echo sprintf('<option value="%d" %s>%s</option>',
                                    $id, ($info['slaId']==$id)?'selected="selected"':'',$name);
                        }
                    }
                    ?>
                </select>
                &nbsp;<font class="error">&nbsp;<?php echo $errors['slaId']; ?></font>
            </td>
         </tr>

         <tr>
            <td width="160">
                <?php echo __('Due Date');?>:
            </td>
            <td>
                <?php
                $duedateField = Ticket::duedateField('duedate', $info['duedate']);
                $duedateField->render();
                ?>
                &nbsp;<font class="error">&nbsp;<?php echo $errors['duedate']; ?> &nbsp; <?php echo $errors['time']; ?></font>
                <em><?php echo __('Time is based on your time
                        zone');?>&nbsp;(<?php echo $cfg->getTimezone($thisstaff); ?>)</em>
            </td>
        </tr>

        <?php
        if($thisstaff->hasPerm(Ticket::PERM_ASSIGN, false)) { ?>
        <tr>
            <td width="160"><?php echo __('Assign To');?>:</td>
            <td>
                <select id="assignId" name="assignId">
                    <option value="0" selected="selected">&mdash; <?php echo __('Select an Agent OR a Team');?> &mdash;</option>
                    <?php
                    $users = Staff::getStaffMembers(array(
                                'available' => true,
                                'staff' => $thisstaff,
                                ));
                    if ($users) {
                        echo '<OPTGROUP label="'.sprintf(__('Agents (%d)'), count($users)).'">';
                        foreach ($users as $id => $name) {
                            $k="s$id";
                            echo sprintf('<option value="%s" %s>%s</option>',
                                        $k, (($info['assignId']==$k) ? 'selected="selected"' : ''), $name);
                        }
                        echo '</OPTGROUP>';
                    }

                    if(($teams=Team::getActiveTeams())) {
                        echo '<OPTGROUP label="'.sprintf(__('Teams (%d)'), count($teams)).'">';
                        foreach($teams as $id => $name) {
                            $k="t$id";
                            echo sprintf('<option value="%s" %s>%s</option>',
                                        $k,(($info['assignId']==$k)?'selected="selected"':''),$name);
                        }
                        echo '</OPTGROUP>';
                    }
                    ?>
                </select>&nbsp;<span class='error'>&nbsp;<?php echo $errors['assignId']; ?></span>
            </td>
        </tr>
        <?php } ?>
        </tbody>
        <tbody id="dynamic-form">
        <?php
            $options = array('mode' => 'create');
            foreach ($forms as $form) {
                print $form->getForm($_SESSION[':form-data'])->getMedia();
                include(STAFFINC_DIR .  'templates/dynamic-form.tmpl.php');
            }
        ?>
        </tbody>
        <tbody>
        <?php
        //is the user allowed to post replies??
        if ($thisstaff->getRole()->hasPerm(Ticket::PERM_REPLY)) { ?>
        <tr>
            <th colspan="2">
                <em><strong><?php echo __('Response');?></strong>: <?php echo __('Optional response to the above issue.');?></em>
            </th>
        </tr>
        <tr>
            <td colspan=2>
            <?php
            if($cfg->isCannedResponseEnabled() && ($cannedResponses=Canned::getCannedResponses())) {
                ?>
                <div style="margin-top:0.3em;margin-bottom:0.5em">
                    <?php echo __('Canned Response');?>:&nbsp;
                    <select id="cannedResp" name="cannedResp">
                        <option value="0" selected="selected">&mdash; <?php echo __('Select a canned response');?> &mdash;</option>
                        <?php
                        foreach($cannedResponses as $id =>$title) {
                            echo sprintf('<option value="%d">%s</option>',$id,$title);
                        }
                        ?>
                    </select>
                    &nbsp;&nbsp;
                    <label class="checkbox inline"><input type='checkbox' value='1' name="append" id="append" checked="checked"><?php echo __('Append');?></label>
                </div>
            <?php
            }
                $signature = '';
                if ($thisstaff->getDefaultSignatureType() == 'mine')
                    $signature = $thisstaff->getSignature(); ?>
                <textarea
                    class="<?php if ($cfg->isRichTextEnabled()) echo 'richtext';
                        ?> draft draft-delete" data-signature="<?php
                        echo Format::viewableImages(Format::htmlchars($signature, true)); ?>"
                    data-signature-field="signature" data-dept-field="deptId"
                    placeholder="<?php echo __('Initial response for the ticket'); ?>"
                    name="response" id="response" cols="21" rows="8"
                    style="width:80%;" <?php
    list($draft, $attrs) = Draft::getDraftAndDataAttrs('ticket.staff.response', false, $info['response']);
    echo $attrs; ?>><?php echo ThreadEntryBody::clean($_POST ? $info['response'] : $draft);
                ?></textarea>
                    <div class="attachments">
<?php
print $response_form->getField('attachments')->render();
?>
                    </div>

                <table border="0" cellspacing="0" cellpadding="2" width="100%">
            <tr>
                <td width="100"><?php echo __('Ticket Status');?>:</td>
                <td>
                    <select name="statusId">
                    <?php
                    $statusId = $info['statusId'] ?: $cfg->getDefaultTicketStatusId();
                    $states = array('open');
                    if ($thisstaff->hasPerm(Ticket::PERM_CLOSE, false))
                        $states = array_merge($states, array('closed'));
                    foreach (TicketStatusList::getStatuses(
                                array('states' => $states)) as $s) {
                        if (!$s->isEnabled()) continue;
                        $selected = ($statusId == $s->getId());
                        echo sprintf('<option value="%d" %s>%s</option>',
                                $s->getId(),
                                $selected
                                 ? 'selected="selected"' : '',
                                __($s->getName()));
                    }
                    ?>
                    </select>
                </td>
            </tr>
             <tr>
                <td width="100"><?php echo __('Signature');?>:</td>
                <td>
                    <?php
                    $info['signature']=$info['signature']?$info['signature']:$thisstaff->getDefaultSignatureType();
                    ?>
                    <label><input type="radio" name="signature" value="none" checked="checked"> <?php echo __('None');?></label>
                    <?php
                    if($thisstaff->getSignature()) { ?>
                        <label><input type="radio" name="signature" value="mine"
                            <?php echo ($info['signature']=='mine')?'checked="checked"':''; ?>> <?php echo __('My Signature');?></label>
                    <?php
                    } ?>
                    <label><input type="radio" name="signature" value="dept"
                        <?php echo ($info['signature']=='dept')?'checked="checked"':''; ?>> <?php echo sprintf(__('Department Signature (%s)'), __('if set')); ?></label>
                </td>
             </tr>
            </table>
            </td>
        </tr>
        <?php
        } //end canPostReply
        ?>
        <tr>
            <th colspan="2">
                <em><strong><?php echo __('Internal Note');?></strong>
                <font class="error">&nbsp;<?php echo $errors['note']; ?></font></em>
            </th>
        </tr>
        <tr>
            <td colspan=2>
                <textarea
                    class="<?php if ($cfg->isRichTextEnabled()) echo 'richtext';
                        ?> draft draft-delete"
                    placeholder="<?php echo __('Optional internal note (recommended on assignment)'); ?>"
                    name="note" cols="21" rows="6" style="width:80%;" <?php
    list($draft, $attrs) = Draft::getDraftAndDataAttrs('ticket.staff.note', false, $info['note']);
    echo $attrs; ?>><?php echo ThreadEntryBody::clean($_POST ? $info['note'] : $draft);
                ?></textarea>
            </td>
        </tr>
    </tbody>
</table>
<p style="text-align:center;">
    <input type="submit" name="submit" value="<?php echo _P('action-button', 'Open');?>">
    <input type="reset"  name="reset"  value="<?php echo __('Reset');?>">
    <input type="button" name="cancel" value="<?php echo __('Cancel');?>" onclick="javascript:
        $(this.form).find('textarea.richtext')
          .redactor('plugin.draft.deleteDraft');
        window.location.href='tickets.php'; " />
</p>
</form>
<script type="text/javascript">
$(function() {
    $('input#user-email').typeahead({
        source: function (typeahead, query) {
            $.ajax({
                url: "ajax.php/users?q="+query,
                dataType: 'json',
                success: function (data) {
                    typeahead.process(data);
                }
            });
        },
        onselect: function (obj) {
            $('#uid').val(obj.id);
            $('#user-name').val(obj.name);
            $('#user-email').val(obj.email);
        },
        property: "/bin/true"
    });

   <?php
    // Popup user lookup on the initial page load (not post) if we don't have a
    // user selected
    if (!$_POST && !$user) {?>
    setTimeout(function() {
      $.userLookup('ajax.php/users/lookup/form', function (user) {
        window.location.href = window.location.href+'&uid='+user.id;
      });
    }, 100);
    <?php
    } ?>
});

$(function() {
    $('a#editorg').click( function(e) {
        e.preventDefault();
        $('div#org-profile').hide();
        $('div#org-form').fadeIn();
        return false;
     });

    $(document).on('click', 'form.org input.cancel', function (e) {
        e.preventDefault();
        $('div#org-form').hide();
        $('div#org-profile').fadeIn();
        return false;
    });

    $('.userSelection').select2({
      width: '450px',
      minimumInputLength: 3,
      ajax: {
        url: "ajax.php/users/local",
        dataType: 'json',
        data: function (params) {
          return {
            q: params.term,
          };
        },
        processResults: function (data) {
          return {
            results: $.map(data, function (item) {
              return {
                text: item.email + ' - ' + item.name,
                slug: item.slug,
                email: item.email,
                id: item.id
              }
            })
          };
          $('#user-email').val(item.name);
        }
      }
    });

    $('.userSelection').on('select2:select', function (e) {
      var data = e.params.data;
      $('#user-email').val(data.email);
    });

    $('.userSelection').on("change", function (e) {
      var data = $('.userSelection').select2('data');
      var data = data[0].text;
      var email = data.substr(0,data.indexOf(' '));
      $('#user-email').val(data.substr(0,data.indexOf(' ')));
     });

    $('.collabSelections').select2({
      width: '450px',
      minimumInputLength: 3,
      ajax: {
        url: "ajax.php/users/local",
        dataType: 'json',
        data: function (params) {
          return {
            q: params.term,
          };
        },
        processResults: function (data) {
          return {
            results: $.map(data, function (item) {
              return {
                text: item.name,
                slug: item.slug,
                id: item.id
              }
            })
          };
        }
      }
    });

  });
</script>


All above files are in /include or /include/staff
Below in scp
scp/tickets.php:
<?php
/*************************************************************************
    tickets.php

    Handles all tickets related actions.

    Peter Rotich <peter@osticket.com>
    Copyright (c)  2006-2013 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:
**********************************************************************/

require('staff.inc.php');
require_once(INCLUDE_DIR.'class.ticket.php');
require_once(INCLUDE_DIR.'class.dept.php');
require_once(INCLUDE_DIR.'class.filter.php');
require_once(INCLUDE_DIR.'class.canned.php');
require_once(INCLUDE_DIR.'class.json.php');
require_once(INCLUDE_DIR.'class.dynamic_forms.php');
require_once(INCLUDE_DIR.'class.export.php');       // For paper sizes



// Fetch ticket queues organized by root and sub-queues
$queues = CustomQueue::getHierarchicalQueues($thisstaff);

$page='';
$ticket = $user = null; //clean start.
$redirect = false;
//LOCKDOWN...See if the id provided is actually valid and if the user has access.
if(isset($_REQUEST['id']) || isset($_REQUEST['number'])) {
    if($_REQUEST['id'] && !($ticket=Ticket::lookup($_REQUEST['id'])))
         $errors['err']=sprintf(__('%s: Unknown or invalid ID.'), __('ticket'));
    elseif($_REQUEST['number'] && !($ticket=Ticket::lookup(array('number' => $_REQUEST['number']))))
         $errors['err']=sprintf(__('%s: Unknown or invalid number.'), __('ticket'));
     elseif(!$ticket || !$ticket->checkStaffPerm($thisstaff)) {
         $errors['err']=__('Access denied. Contact admin if you believe this is in error');
         $ticket=null; //Clear ticket obj.
     }
}

if (!$ticket) {
    // Display a ticket queue. Decide the contents
    $queue_id = null;

    // Search for user
    if (isset($_REQUEST['uid']))
        $user = User::lookup($_REQUEST['uid']);

    if (isset($_REQUEST['email']))
        $user = User::lookupByEmail($_REQUEST['email']);

    if ($user
            && $_GET['a'] !== 'open'
    ) {
        $criteria = [
            ['user__emails__address', 'equal', $user->getDefaultEmailAddress()],
            ['user_id', 'equal', $user->id],
        ];
        if ($S = $_GET['status'])
            // The actual state is tracked by the key
            $criteria[] = ['status__state', 'includes', [$S => $S]];
        $_SESSION['advsearch']['uid'] = $criteria;
        $queue_id = "adhoc,uid";
    }
    // Search for organization tickets
    elseif (isset($_GET['orgid'])
        && ($org = Organization::lookup($_GET['orgid']))
    ) {
        $criteria = [
            ['user__org__name', 'equal', $org->name],
            ['user__org_id', 'equal', $org->id],
        ];
        if ($S = $_GET['status'])
            $criteria[] = ['status__state', 'includes', [$S => $S]];
        $_SESSION['advsearch']['orgid'] = $criteria;
        $queue_id = "adhoc,orgid";
    }
    // Basic search (click on 🔍 )
    elseif (isset($_GET['a']) && $_GET['a'] === 'search'
        && ($_GET['query'])
    ) {
        $wc = mb_str_wc($_GET['query']);
        if ($wc < 4) {
            $key = substr(md5($_GET['query']), -10);
            if ($_GET['search-type'] == 'typeahead'
                    || Validator::is_emailish($_GET['query'])) {
                // Use a faster index
                $criteria = [
                    'user__emails__address',
                    Validator::is_valid_email($_GET['query']) ? 'equal' : 'contains',
                    $_GET['query']
                ];
            } elseif (Validator::is_numeric($_GET['query'])) {
                $criteria = ['number', 'contains', $_GET['query']];
            } else {
                $criteria = [':keywords', null, $_GET['query']];
            }
            $_SESSION['advsearch'][$key] = [$criteria];
            $queue_id = "adhoc,{$key}";
        } else {
            $errors['err'] = sprintf(
                    __('Search term cannot have more than %d keywords'), 4);
        }
    }

    $queue_key = sprintf('::Q:%s', ObjectModel::OBJECT_TYPE_TICKET);
    $queue_id = $queue_id ?: @$_GET['queue'] ?: $_SESSION[$queue_key]
        ?? $thisstaff->getDefaultTicketQueueId() ?: $cfg->getDefaultTicketQueueId();

    // Recover advanced search, if requested
    if (isset($_SESSION['advsearch'])
        && strpos($queue_id, 'adhoc') === 0
    ) {
        list(,$key) = explode(',', $queue_id, 2);
        // For queue=queue, use the most recent search
        if (!$key) {
            reset($_SESSION['advsearch']);
            $key = key($_SESSION['advsearch']);
        }

        $queue = AdhocSearch::load($key);
    }

    if ((int) $queue_id && !isset($queue))
        $queue = SavedQueue::lookup($queue_id);

    if (!$queue && ($qid=$cfg->getDefaultTicketQueueId()))
        $queue = SavedQueue::lookup($qid);

    if (!$queue && $queues)
        list($queue,) = $queues[0];

    if ($queue) {
        // Set the queue_id for navigation to turn a top-level item bold
        $_REQUEST['queue'] = $queue->getId();
        // Make the current queue sticky
         $_SESSION[$queue_key] = $queue->getId();
    }
}

// Configure form for file uploads
$response_form = new SimpleForm(array(
    'attachments' => new FileUploadField(array('id'=>'attach',
        'name'=>'attach:response',
        'configuration' => array('extensions'=>'')))
));
$note_form = new SimpleForm(array(
    'attachments' => new FileUploadField(array('id'=>'attach',
        'name'=>'attach:note',
        'configuration' => array('extensions'=>'')))
));

//At this stage we know the access status. we can process the post.
if($_POST && !$errors):

    if($ticket && $ticket->getId()) {
        //More coffee please.
        $errors=array();
        $lock = $ticket->getLock(); //Ticket lock if any
        $role = $ticket->getRole($thisstaff);
        $dept = $ticket->getDept();
        $isManager = $dept->isManager($thisstaff); //Check if Agent is Manager
        switch(strtolower($_POST['a'])):
        case 'reply':
            if (!$role || !$role->hasPerm(Ticket::PERM_REPLY)) {
                $errors['err'] = __('Action denied. Contact admin for access');
            } else {
                $vars = $_POST;
                $vars['files'] = $response_form->getField('attachments')->getFiles();
                $vars['response'] = ThreadEntryBody::clean($vars['response']);
                if(!$vars['response'])
                    $errors['response']=__('Response required');

                if ($cfg->isTicketLockEnabled()) {
                    if (!$lock) {
                        $errors['err'] = sprintf('%s %s', __('This action requires a lock.'), __('Please try again!'));
                    }
                    // Use locks to avoid double replies
                    elseif ($lock->getStaffId()!=$thisstaff->getId()) {
                        $errors['err'] = __('Action Denied. Ticket is locked by someone else!');
                    }
                    // Attempt to renew the lock if possible
                    elseif (($lock->isExpired() && !$lock->renew())
                        ||($lock->getCode() != $_POST['lockCode'])
                    ) {
                        $errors['err'] = sprintf('%s %s', __('Your lock has expired.'), __('Please try again!'));
                    }
                }

                //Make sure the email is not banned
                if(!$errors['err'] && Banlist::isBanned($ticket->getEmail()))
                    $errors['err']=__('Email is in banlist. Must be removed to reply.');
            }

            $alert =  strcasecmp('none', $_POST['reply-to']);
            if (!$errors) {
                // Add new collaborators (if any)
                $_errors = array();
                if (isset($vars['ccs']) && count($vars['ccs']))
                    $ticket->addCollaborators($vars['ccs'], array(), $_errors);
                // set status of collaborators
                if ($collabs = $ticket->getCollaborators()) {
                    foreach ($collabs as $collaborator) {
                        $cid = $collaborator->getUserId();
                        // Enable collaborators if they were reselected
                        if (!$collaborator->isActive() && ($vars['ccs'] && in_array($cid, $vars['ccs'])))
                            $collaborator->setFlag(Collaborator::FLAG_ACTIVE, true);
                        // Disable collaborators if they were unchecked
                        elseif ($collaborator->isActive() && (!$vars['ccs'] || !in_array($cid, $vars['ccs'])))
                            $collaborator->setFlag(Collaborator::FLAG_ACTIVE, false);
                        $collaborator->save();
                    }
                }
            }
            if (!$errors && ($response=$ticket->postReply($vars, $errors,
                            $alert))) {
                $msg = sprintf(__('%s: Reply posted successfully'),
                        sprintf(__('Ticket #%s'),
                            sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
                                $ticket->getId(), $ticket->getNumber()))
                        );

                // Clear attachment list
                $response_form->setSource(array());
                $response_form->getField('attachments')->reset();

                // Remove staff's locks
                $ticket->releaseLock($thisstaff->getId());

                // Cleanup response draft for this user
                Draft::deleteForNamespace(
                    'ticket.response.' . $ticket->getId(),
                    $thisstaff->getId());

                if ($ticket->isClosed())
                    $ticket = null;

                $redirect = 'tickets.php';
                if ($ticket && $thisstaff->getReplyRedirect() == 'Ticket')
                    $redirect = 'tickets.php?id='.$ticket->getId();

            } elseif (!$errors['err']) {
                $errors['err']=sprintf('%s %s',
                    __('Unable to post the reply.'),
                    __('Correct any errors below and try again.'));
            }
            break;
        case 'postnote': /* Post Internal Note */
            $vars = $_POST;
            $vars['files'] = $note_form->getField('attachments')->getFiles();
            $vars['note'] = ThreadEntryBody::clean($vars['note']);

            if ($cfg->isTicketLockEnabled()) {
                if (!$lock) {
                    $errors['err'] = sprintf('%s %s', __('This action requires a lock.'), __('Please try again!'));
                }
                // Use locks to avoid double replies
                elseif ($lock->getStaffId()!=$thisstaff->getId()) {
                    $errors['err'] = __('Action Denied. Ticket is locked by someone else!');
                }
                elseif ($lock->getCode() != $_POST['lockCode']) {
                    $errors['err'] = sprintf('%s %s', __('Your lock has expired.'), __('Please try again!'));
                }
            }

            $wasOpen = ($ticket->isOpen());
            if(($note=$ticket->postNote($vars, $errors, $thisstaff))) {

                $msg = sprintf(__('%s: %s posted successfully'),
                        sprintf(__('Ticket #%s'),
                            sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
                                $ticket->getId(), $ticket->getNumber())),
                        __('Internal note')
                        );
                // Clear attachment list
                $note_form->setSource(array());
                $note_form->getField('attachments')->reset();

                // Remove staff's locks
                $ticket->releaseLock($thisstaff->getId());

                if($wasOpen && $ticket->isClosed())
                    $ticket = null; //Going back to main listing.
                else
                    // Ticket is still open -- clear draft for the note
                    Draft::deleteForNamespace('ticket.note.'.$ticket->getId(),
                        $thisstaff->getId());

                 $redirect = 'tickets.php';
                 if ($ticket)
                     $redirect ='tickets.php?id='.$ticket->getId();

            } else {

                if(!$errors['err'])
                    $errors['err'] = __('Unable to post internal note - missing or invalid data.');

                $errors['postnote'] = sprintf('%s %s',
                    __('Unable to post the note.'),
                    __('Correct any errors below and try again.'));
            }
            break;
        case 'edit':
        case 'update':
            if(!$ticket || !$role->hasPerm(Ticket::PERM_EDIT))
                $errors['err']=__('Permission Denied. You are not allowed to edit tickets');
            elseif($ticket->update($_POST,$errors)) {
                $msg=__('Ticket updated successfully');
                $redirect = 'tickets.php?id='.$ticket->getId();
                $_REQUEST['a'] = null; //Clear edit action - going back to view.
                //Check to make sure the staff STILL has access post-update (e.g dept change).
                if(!$ticket->checkStaffPerm($thisstaff))
                    $ticket=null;
            } elseif(!$errors['err']) {
                $errors['err']=sprintf('%s %s',
                    sprintf(__('Unable to update %s.'), __('this ticket')),
                    __('Correct any errors below and try again.')
                );
            }
            break;
        case 'process':
            switch(strtolower($_POST['do'])):
                case 'claim':
                    if(!$role->hasPerm(Ticket::PERM_EDIT)) {
                        $errors['err'] = __('Permission Denied. You are not allowed to assign/claim tickets.');
                    } elseif(!$ticket->isOpen()) {
                        $errors['err'] = __('Only open tickets can be assigned');
                    } elseif($ticket->isAssigned()) {
                        $errors['err'] = sprintf(__('Ticket is already assigned to %s'),$ticket->getAssigned());
                    } elseif ($ticket->claim()) {
                        $msg = __('Ticket is now assigned to you!');
                    } else {
                        $errors['err'] = sprintf('%s %s', __('Problems assigning the ticket.'), __('Please try again!'));
                    }
                    break;
                case 'overdue':
                    if(!$dept || !$isManager) {
                        $errors['err']=__('Permission Denied. You are not allowed to flag tickets overdue');
                    } elseif($ticket->markOverdue()) {
                        $msg=sprintf(__('Ticket flagged as overdue by %s'),$thisstaff->getName());
                        $ticket->logActivity(__('Ticket Marked Overdue'),$msg);
                    } else {
                        $errors['err']=sprintf('%s %s', __('Problems marking the the ticket overdue.'), __('Please try again!'));
                    }
                    break;
                case 'banemail':
                    if (!$thisstaff->hasPerm(Email::PERM_BANLIST)) {
                        $errors['err']=__('Permission Denied. You are not allowed to ban emails');
                    } elseif(BanList::includes($ticket->getEmail())) {
                        $errors['err']=__('Email already in banlist');
                    } elseif(Banlist::add($ticket->getEmail(),$thisstaff->getName())) {
                        $msg=sprintf(__('Email %s added to banlist'),$ticket->getEmail());
                    } else {
                        $errors['err']=__('Unable to add the email to banlist');
                    }
                    break;
                case 'unbanemail':
                    if (!$thisstaff->hasPerm(Email::PERM_BANLIST)) {
                        $errors['err'] = __('Permission Denied. You are not allowed to remove emails from banlist.');
                    } elseif(Banlist::remove($ticket->getEmail())) {
                        $msg = __('Email removed from banlist');
                    } elseif(!BanList::includes($ticket->getEmail())) {
                        $warn = __('Email is not in the banlist');
                    } else {
                        $errors['err']=sprintf('%s %s', __('Unable to remove the email from banlist.'), __('Please try again!'));
                    }
                    break;
                case 'changeuser':
                    if (!$role->hasPerm(Ticket::PERM_EDIT)) {
                        $errors['err']=__('Permission Denied. You are not allowed to edit tickets');
                    } elseif (!$_POST['user_id'] || !($user=User::lookup($_POST['user_id']))) {
                        $errors['err'] = __('Unknown user selected');
                    } elseif ($ticket->changeOwner($user)) {
                        $msg = sprintf(__('Ticket ownership changed to %s'),
                            Format::htmlchars($user->getName()));
                    } else {
                        $errors['err'] = sprintf('%s %s', __('Unable to change ticket ownership.'), __('Please try again!'));
                    }
                    break;
                case 'addcc':
                    if (!$role->hasPerm(Ticket::PERM_EDIT)) {
                        $errors['err']=__('Permission Denied. You are not allowed to add collaborators');
                    } elseif (!$_POST['user_id'] || !($user=User::lookup($_POST['user_id']))) {
                        $errors['err'] = __('Unknown user selected');
                  } elseif ($c2 = $ticket->addCollaborator($user, array(), $errors)) {
                        $c2->setFlag(Collaborator::FLAG_CC, true);
                        $c2->save();
                        $msg = sprintf(__('Collaborator %s added'),
                            Format::htmlchars($user->getName()));
                    }
                    else {
                      $errors['err'] = sprintf('%s %s', __('Unable to add collaborator.'), __('Please try again!'));
                    }
                    break;
                default:
                    $errors['err']=__('You must select action to perform');
            endswitch;
            break;
        default:
            $errors['err']=__('Unknown action');
        endswitch;
    }elseif($_POST['a']) {

        switch($_POST['a']) {
            case 'open':
                $ticket=null;
                if (!$thisstaff ||
                        !$thisstaff->hasPerm(Ticket::PERM_CREATE, false)) {
                     $errors['err'] = sprintf('%s %s',
                             sprintf(__('You do not have permission %s'),
                                 __('to create tickets')),
                             __('Contact admin for such access'));
                } else {
                    $vars = $_POST;

                    if ($vars['uid'] && !($user=User::lookup($vars['uid'])))
                        $vars['uid'] = 0;

                    $vars['files'] = $response_form->getField('attachments')->getFiles();

                    if(($ticket=Ticket::open($vars, $errors))) {
                        $msg=__('Ticket created successfully');
                        $redirect = 'tickets.php?id='.$ticket->getId();
                        $_REQUEST['a']=null;
                        if (!$ticket->checkStaffPerm($thisstaff) || $ticket->isClosed())
                            $ticket=null;
                        Draft::deleteForNamespace('ticket.staff%', $thisstaff->getId());
                        // Drop files from the response attachments widget
                        $response_form->setSource(array());
                        $response_form->getField('attachments')->reset();
                        $_SESSION[':form-data'] = null;
                        // Regenerate Session ID
                        $thisstaff->regenerateSession();
                    } elseif(!$errors['err']) {
                        // ensure that we retain the tid if ticket is created from thread
                        if ($_SESSION[':form-data']['ticketId'] || $_SESSION[':form-data']['taskId'])
                            $_GET['tid'] = $_SESSION[':form-data']['ticketId'] ?: $_SESSION[':form-data']['taskId'];

                        $errors['err']=sprintf('%s %s',
                            __('Unable to create the ticket.'),
                            __('Correct any errors below and try again.'));
                    }
                }
                break;
        }
    }
    if(!$errors)
        $thisstaff ->resetStats(); //We'll need to reflect any changes just made!
endif;

if ($redirect) {
    if ($msg)
        Messages::success($msg);
    Http::redirect($redirect);
}

// Clear advanced search upon request
if (isset($_GET['clear_filter']))
    unset($_SESSION['advsearch']);

//Navigation
$nav->setTabActive('tickets');
$nav->addSubNavInfo('jb-overflowmenu', 'customQ_nav');

// Start with all the top-level (container) queues
foreach ($queues as $_) {
    list($q, $children) = $_;
    if ($q->isPrivate())
        continue;
    $nav->addSubMenu(function() use ($q, $queue, $children) {
        // A queue is selected if it is the one being displayed. It is
        // "child" selected if its ID is in the path of the one selected
        $_selected = ($queue && $queue->getId() == $q->getId());
        $child_selected = $queue
            && ($queue->parent_id == $q->getId()
                || false !== strpos($queue->getPath(), "/{$q->getId()}/"));
        include STAFFINC_DIR . 'templates/queue-navigation.tmpl.php';

        return ($child_selected || $_selected);
    });
}

// Add my advanced searches
$nav->addSubMenu(function() use ($queue) {
    global $thisstaff;
    $selected = false;
    // A queue is selected if it is the one being displayed. It is
    // "child" selected if its ID is in the path of the one selected
    $child_selected = $queue instanceof SavedSearch;
    include STAFFINC_DIR . 'templates/queue-savedsearches-nav.tmpl.php';
    return ($child_selected || $selected);
});


if ($thisstaff->hasPerm(Ticket::PERM_CREATE, false)) {
    $nav->addSubMenu(array('desc'=>__('New Ticket'),
                           'title'=> __('Open a New Ticket'),
                           'href'=>'tickets.php?a=open',
                           'iconclass'=>'newTicket',
                           'id' => 'new-ticket'),
                        (isset($_REQUEST['a']) && $_REQUEST['a']=='open'));
}


$ost->addExtraHeader('<script type="text/javascript" src="js/ticket.js?0375576"></script>');
$ost->addExtraHeader('<script type="text/javascript" src="js/thread.js?0375576"></script>');
$ost->addExtraHeader('<meta name="tip-namespace" content="tickets.queue" />',
    "$('#content').data('tipNamespace', 'tickets.queue');");

if($ticket) {
    $ost->setPageTitle(sprintf(__('Ticket #%s'),$ticket->getNumber()));
    $nav->setActiveSubMenu(-1);
    $inc = 'ticket-view.inc.php';
    if ($_REQUEST['a']=='edit'
            && $ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT)) {
        $inc = 'ticket-edit.inc.php';
        if (!$forms) $forms=DynamicFormEntry::forTicket($ticket->getId());
        // Auto add new fields to the entries
        foreach ($forms as $f) {
            $f->filterFields(function($f) { return !$f->isStorable(); });
            $f->addMissingFields();
        }
    } elseif($_REQUEST['a'] == 'print') {
        if (!extension_loaded('mbstring'))
            $errors['err'] = sprintf('%s %s',
                'mbstring',
                __('extension required to print ticket to PDF'));
        elseif (!$ticket->pdfExport($_REQUEST['psize'], $_REQUEST['notes'], $_REQUEST['events']))
            $errors['err'] = __('Unable to export the ticket to PDF for print.')
                .' '.__('Internal error occurred');
    } elseif ($_GET['a'] == 'zip' && !$ticket->zipExport($_REQUEST['notes'], $_REQUEST['tasks'])) {
        $errors['err'] = __('Unable to export the ticket to ZIP.')
            .' '.__('Internal error occurred');
    } elseif (PluginManager::auditPlugin() && $_REQUEST['a'] == 'export' && strtolower($_REQUEST['t']) == 'audits') {
      require_once(sprintf('phar:///%s/plugins/audit.phar/class.audit.php', INCLUDE_DIR));
      $show = AuditEntry::$show_view_audits;
      $filename = sprintf('%s-audits-%s.csv',
              $ticket->getNumber(), date('Ymd'));
      $tableInfo = AuditEntry::getTableInfo($ticket, true);
      if (!Export::audits('ticket', $filename, $tableInfo, $ticket, 'csv', $show))
          $errors['err'] = __('Unable to dump query results.')
              .' '.__('Internal error occurred');
    }
} else {
    $inc = 'templates/queue-tickets.tmpl.php';
    if ((isset($_REQUEST['a']) && $_REQUEST['a']=='open') &&
            $thisstaff->hasPerm(Ticket::PERM_CREATE, false)) {
        $inc = 'ticket-open.inc.php';
    } elseif ($queue) {
        // XXX: Check staff access?
        $quick_filter = @$_REQUEST['filter'];
        $tickets = $queue->getQuery(false, $quick_filter);
    }

    //set refresh rate if the user has it configured
    if(!$_POST && !isset($_REQUEST['a']) && ($min=(int)$thisstaff->getRefreshRate())) {
        $js = "+function(){ var qq = setInterval(function() { if ($.refreshTicketView === undefined) return; clearInterval(qq); $.refreshTicketView({$min}*60000); }, 200); }();";
        $ost->addExtraHeader('<script type="text/javascript">'.$js.'</script>',
            $js);
    }
}

require_once(STAFFINC_DIR.'header.inc.php');
require_once(STAFFINC_DIR.$inc);
print $response_form->getMedia();
require_once(STAFFINC_DIR.'footer.inc.php');


scp/js/ticket.js:
/*********************************************************************
    ticket.js

    Ticket utility loaded on ticket view!

    Useful for UI config settings, ticket locking ...etc

    Peter Rotich <peter@osticket.com>
    Copyright (c) 2006-2013 osTicket
    http://www.osticket.com

    Released under the GNU General Public License WITHOUT ANY WARRANTY.

    vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
+function( $ ) {
  var Lock = function(element, options) {
    this.$element = $(element);
    this.options = $.extend({}, $.fn.exclusive.defaults, options);
    if (!this.$element.data('lockObjectId'))
      return;
    this.objectId = this.$element.data('lockObjectId');
    this.fails = 0;
    this.disabled = false;
    getConfig().then(function(c) {
      if (c.lock_time)
        this.setup(options.lockId || this.$element.data('lockId') || undefined);
    }.bind(this));
  }

  Lock.prototype = {
    constructor: Lock,
    registry: [],

    setup: function(lockId) {
      // When something inside changes or is clicked which requires a lock,
      // attempt to fetch one (lazily)
      $(':input', this.$element).on('keyup, change', this.acquire.bind(this));
      $(':submit', this.$element).click(this.ensureLocked.bind(this));

      // If lock already held, assume full time of lock remains, but warn
      // user about pending expiration
      if (lockId) {
        getConfig().then(function(c) {
          this.update({id: lockId, time: c.lock_time - 10});
        }.bind(this));
      }
    },

    acquire: function() {
      if (this.lockId)
        return this.renew();
      if (this.nextRenew && new Date().getTime() < this.nextRenew)
        return this.locked;
      if (this.disabled || this.ajaxActive)
        return this.locked;

      this.ajaxActive = $.ajax({
        type: "POST",
        url: 'ajax.php/lock/'+this.objectId,
        dataType: 'json',
        cache: false,
        success: $.proxy(this.update, this),
        error: $.proxy(this.retry, this, this.acquire),
        complete: $.proxy(function() { this.ajaxActive = false; }, this)
      });
      return this.locked = $.Deferred();
    },

    renew: function() {
      if (!this.lockId)
        return;
      if (this.nextRenew && new Date().getTime() < this.nextRenew)
        return this.locked;
      if (this.disabled || this.ajaxActive)
        return this.locked;

      this.ajaxActive = $.ajax({
        type: "POST",
        url: 'ajax.php/lock/{0}/{1}/renew'.replace('{0}',this.lockId).replace('{1}',this.objectId),
        dataType: 'json',
        cache: false,
        success: $.proxy(this.update, this),
        error: $.proxy(this.retry, this, this.renew),
        complete: $.proxy(function() { this.ajaxActive = false; }, this)
      });
      return this.locked = $.Deferred();
    },

    wakeup: function(e) {
      // Click handler from message bar. Bar will be manually hidden when
      // lock is re-acquired
      this.renew();
      return false;
    },

    retry: function(func, xhr, textStatus, response) {
      var json = xhr ? xhr.responseJSON : response;

      if (xhr.status == 418) {
          this.disabled = true;
          return this.destroy();
      }

      if ((typeof json == 'object' && !json.retry) || !this.options.retry)
        return this.fail(json.msg);
      if (typeof json == 'object' && json.retry == 'acquire') {
        // Lock no longer exists server-side
        this.destroy();
        setTimeout(this.acquire.bind(this), 2);
      }
      if (++this.fails > this.options.maxRetries)
        // Attempt to acquire a new lock ?
        return this.fail(json ? json.msg : null);
      this.retryTimer = setTimeout($.proxy(func, this), this.options.retryInterval * 1000);
    },

    release: function() {
      if (!this.lockId)
        return false;
      if (this.ajaxActive)
        this.ajaxActive.abort();

      $.ajax({
        type: 'POST',
        url: 'ajax.php/lock/{0}/release'.replace('{0}', this.lockId),
        data: 'delete',
        cache: false,
        success: this.clearAll.bind(this),
        complete: this.destroy.bind(this)
      });
    },

    clearAll: function() {
      // Clear all other current locks with the same ID as this
      $.each(Lock.prototype.registry, function(i, l) {
        if (l.lockId && l.lockId == this.lockId)
          l.shutdown();
      }.bind(this));
    },

    shutdown: function() {
      clearTimeout(this.warning);
      clearTimeout(this.retryTimer);
      $(document).off('.exclusive');
    },

    destroy: function() {
      this.shutdown();
      delete this.lockId;
      $(this.options.lockInput, this.$element).val('');
      if (this.locked)
        this.locked.reject();
    },

    update: function(lock) {
      if (typeof lock != 'object' || lock.retry === true) {
        // Non-json response, or retry requested server-side
        return this.retry(this.renew, this.ajaxActive, false, lock);
      }
      if (!lock.id) {
        // Response did not include a lock id number
        return this.fail(lock.msg);
      }
      if (!this.lockId) {
        // Set up release on away navigation
        $(document).off('.exclusive');
        $(document).on('pjax:click.exclusive', $.proxy(this.release, this));
        Lock.prototype.registry.push(this);
      }

      this.lockId = lock.id;
      this.fails = 0;
      $.messageBar.hide();
      this.errorBar = false;

      // If there is an input with the name 'lockCode', then set the value
      // to the lock.code retrieved (if any)
      if (lock.code)
        $(this.options.lockInput, this.$element).val(lock.code);

      // Deadband renew to every 30 seconds
      this.nextRenew = new Date().getTime() + 30000;

      // Warn 10 seconds before expiration
      this.lockTimeout(lock.time - 10);

      if (this.locked)
        this.locked.resolve(lock);
    },

    lockTimeout: function(time) {
      if (this.warning)
        clearTimeout(this.warning);
      this.warning = setTimeout(this.warn.bind(this), time * 1000);
    },

    ensureLocked: function(e) {
      // Make sure a lock code has been fetched first
      if (!$(this.options.lockInput, this.$element).val()) {
        var $target = $(e.target),
            text = $target.text() || $target.val();
        $target.prop('disabled', true).text(__('Acquiring Lock')).val(__('Acquiring Lock'));
        this.acquire().always(function(lock) {
          $target.text(text).val(text).prop('disabled', false);
          if (typeof lock == 'object' && lock.code)
            $target.trigger(e.type, e);
        }.bind(this));
        return false;
      }
    },

    warn: function() {
      $.messageBar.show(
        __('Your lock is expiring soon.'),
        __('The lock you hold on this ticket will expire soon. Would you like to renew the lock?'),
        {onok: this.wakeup.bind(this), buttonText: __("Renew")}
      ).addClass('warning');
    },

    fail: function(msg) {
      // Don't retry for 5 seconds
      this.nextRenew = new Date().getTime() + 5000;
      // Resolve anything awaiting
      if (this.locked)
        this.locked.rejectWith(msg);
      // No longer locked
      this.destroy();
      // Flash the error bar if it's already on the screen
      if (this.errorBar && $.messageBar.visible)
          return this.errorBar.effect('highlight');
      // Add the error bar to the screen
      this.errorBar = $.messageBar.show(
        msg || __('Unable to lock the ticket.'),
        __('Someone else could be working on the same ticket.'),
        {avatar: 'oscar-borg', buttonClass: 'red', dismissible: true}
      ).addClass('danger');
    }
  };

  $.fn.exclusive = function ( option ) {
    return this.each(function () {
      var $this = $(this),
        data = $this.data('exclusive'),
        options = typeof option == 'object' && option;
      if (!data) $this.data('exclusive', (data = new Lock(this, options)));
      if (typeof option == 'string') data[option]();
    });
  };

  $.fn.exclusive.defaults = {
    lockInput: 'input[name=lockCode]',
    maxRetries: 2,
    retry: true,
    retryInterval: 2
  };

  $.fn.exclusive.Constructor = Lock;

}(window.jQuery);

/*
   UI & form events
*/
$.showImagesInline = function(urls, thread_id) {
    var selector = (thread_id == undefined)
        ? '.thread-body img[data-cid]'
        : '.thread-body#thread-entry-'+thread_id+' img[data-cid]';
    $(selector).each(function(i, el) {
        var e = $(el),
            cid = e.data('cid').toLowerCase(),
            info = urls[cid];
        if (info && !e.data('wrapped')) {
            // Add a hover effect with the filename
            var timeout, caption = $('<div class="image-hover">')
                .css({'float':e.css('float')});
            e.wrap(caption).parent()
                .hover(
                    function() {
                        var self = this;
                        timeout = setTimeout(
                            function() { $(self).find('.caption').slideDown(250); },
                            500);
                    },
                    function() {
                        clearTimeout(timeout);
                        $(this).find('.caption').slideUp(250);
                    }
                ).append($('<div class="caption">')
                    .append('<span class="filename">'+info.filename+'</span>')
                    .append($('<a href="'+info.download_url+'" class="action-button pull-right no-pjax"><i class="icon-download-alt"></i> '+__('Download')+'</a>')
                      .attr('download', info.filename)
                    )
                );
            e.data('wrapped', true);
        }
    });
};

$.refreshTicketView = function(interval) {
    var refresh = setInterval(function() {
      if ($('table.list input.ckb[name=tids\\[\\]]:checked').length)
        // Skip the refresh b/c items are checked
        return;
      else if (0 < $('.dialog:visible').length)
        // Dialog open — skip refresh
        return;

      clearInterval(refresh);
      $.pjax({url: document.location.href, container:'#pjax-container', timeout: 30000});
    }, interval);
    $(document).on('pjax:start', function() {
        clearInterval(refresh);
    });
};

var ticket_onload = function($) {
    if (0 === $('#ticketThread').length)
        return;

    $(function(){$('.exclusive[data-lock-object-id]').exclusive();});

    /*** Ticket Actions **/
    //print options TODO: move to backend
    $('a#ticket-print').click(function(e) {
        e.preventDefault();
        $('#overlay').show();
        $('.dialog#print-options').show();
        return false;
    });


    $(document).off('.ticket-action');
    $(document).on('click.ticket-action', 'a.ticket-action', function(e) {
        e.preventDefault();
        var url = 'ajax.php/'
        +$(this).attr('href').substr(1)
        +'?_uid='+new Date().getTime();
        var $redirect = $(this).data('redirect');
        var $options = $(this).data('dialog');
        $.dialog(url, [201], function (xhr) {
            if (!!$redirect)
                window.location.href = $redirect;
            else
                $.pjax.reload('#pjax-container');
        }, $options);

        return false;
    });

    $(document).on('change', 'form[name=reply] select#emailreply', function(e) {
         var $cc = $('form[name=reply] tbody#cc_sec');
        if($(this).val() == 0)
            $cc.hide();
        else
            $cc.show();
     });

};
$(ticket_onload);
$(document).on('pjax:success', function() { ticket_onload(jQuery); });


Give me a complete solution...