Example #1
0
 function cannedResp($id, $format = '')
 {
     global $thisstaff, $_GET;
     include_once INCLUDE_DIR . 'class.canned.php';
     if (!$id || !($canned = Canned::lookup($id)) || !$canned->isEnabled()) {
         Http::response(404, 'No such premade reply');
     }
     //Load ticket.
     if ($_GET['tid']) {
         include_once INCLUDE_DIR . 'class.ticket.php';
         $ticket = Ticket::lookup($_GET['tid']);
     }
     switch ($format) {
         case 'json':
             $resp['id'] = $canned->getId();
             $resp['ticket'] = $canned->getTitle();
             $resp['response'] = $ticket ? $ticket->replaceVars($canned->getResponse()) : $canned->getResponse();
             $resp['files'] = $canned->getAttachments();
             $response = $this->json_encode($resp);
             break;
         case 'txt':
         default:
             $response = $ticket ? $ticket->replaceVars($canned->getResponse()) : $canned->getResponse();
     }
     return $response;
 }
Example #2
0
 function cannedResp($id, $format = 'text')
 {
     global $thisstaff, $cfg;
     include_once INCLUDE_DIR . 'class.canned.php';
     if (!$id || !($canned = Canned::lookup($id)) || !$canned->isEnabled()) {
         Http::response(404, 'No such premade reply');
     }
     if (!$cfg->isHtmlThreadEnabled()) {
         $format .= '.plain';
     }
     return $canned->getFormattedResponse($format);
 }
        ?>
                    <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>
                    <br>
<?php 
    }
    # endif (canned-resonse-enabled)
    $signature = '';
    switch ($thisstaff->getDefaultSignatureType()) {
        case 'dept':
 $tform->render(true);
 ?>
 </tbody>
 <tbody>
 <?php
 //is the user allowed to post replies??
 if($thisstaff->canPostReply()) { ?>
 <tr>
     <th colspan="2">
         <em><strong>Response</strong>: Optional response to the above issue.</em>
     </th>
 </tr>
 <tr>
     <td colspan=2>
     <?php
     if(($cannedResponses=Canned::getCannedResponses())) {
         ?>
         <div style="margin-top:0.3em;margin-bottom:0.5em">
             Canned Response:&nbsp;
             <select id="cannedResp" name="cannedResp">
                 <option value="0" selected="selected">&mdash; Select a canned response &mdash;</option>
                 <?php
                 foreach($cannedResponses as $id =>$title) {
                     echo sprintf('<option value="%d">%s</option>',$id,$title);
                 }
                 ?>
             </select>
             &nbsp;&nbsp;&nbsp;
             <label><input type='checkbox' value='1' name="append" id="append" checked="checked">Append</label>
         </div>
     <?php
Example #5
0
         case 'disable':
             $sql = 'UPDATE ' . CANNED_TABLE . ' SET isenabled=0 ' . ' WHERE canned_id IN (' . implode(',', db_input($_POST['ids'])) . ')';
             if (db_query($sql) && ($num = db_affected_rows())) {
                 if ($num == $count) {
                     $msg = 'Selected canned responses disabled';
                 } else {
                     $warn = "{$num} of {$count} selected canned responses disabled";
                 }
             } else {
                 $errors['err'] = 'Unable to disable selected canned responses';
             }
             break;
         case 'delete':
             $i = 0;
             foreach ($_POST['ids'] as $k => $v) {
                 if (($c = Canned::lookup($v)) && $c->delete()) {
                     $i++;
                 }
             }
             if ($i == $count) {
                 $msg = 'Selected canned responses deleted successfully';
             } elseif ($i > 0) {
                 $warn = "{$i} of {$count} selected canned responses deleted";
             } elseif (!$errors['err']) {
                 $errors['err'] = 'Unable to delete selected canned responses';
             }
             break;
         default:
             $errors['err'] = 'Unknown command';
     }
 }
Example #6
0
 function cannedResponse($tid, $cid, $format = 'text')
 {
     global $thisstaff, $cfg;
     if (!($ticket = Ticket::lookup($tid)) || !$ticket->checkStaffAccess($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}</blockquote><br/>";
         //  Return text if html thread is not enabled
         if (!$cfg->isHtmlThreadEnabled()) {
             $response = Format::html2text($response, 90);
         }
         // XXX: assuming json format for now.
         return Format::json_encode(array('response' => $response));
     }
     if (!$cfg->isHtmlThreadEnabled()) {
         $format .= '.plain';
     }
     $varReplacer = function (&$var) use($ticket) {
         return $ticket->replaceVars($var);
     };
     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);
 }
Example #7
0
 /**
  * Loads data from the I18N_DIR for the target language into the
  * database. This is intended to be done at the time of installation;
  * however, care should be taken in this process to ensure that the
  * process could be repeated if an administrator wanted to change the
  * system language and reload the data.
  */
 function loadDefaultData()
 {
     # notrans -- do not translate the contents of this array
     $models = array('department.yaml' => 'Dept::create', 'sla.yaml' => 'SLA::create', 'form.yaml' => 'DynamicForm::create', 'list.yaml' => 'DynamicList::create', 'help_topic.yaml' => 'Topic::create', 'filter.yaml' => 'Filter::create', 'team.yaml' => 'Team::create', 'organization.yaml' => 'Organization::__create', 'ticket_status.yaml' => 'TicketStatus::__create', 'group.yaml' => 'Group::create', 'file.yaml' => 'AttachmentFile::create', 'sequence.yaml' => 'Sequence::__create');
     $errors = array();
     foreach ($models as $yaml => $m) {
         if ($objects = $this->getTemplate($yaml)->getData()) {
             foreach ($objects as $o) {
                 if ($m && is_callable($m)) {
                     @call_user_func_array($m, array($o, &$errors));
                 }
                 // TODO: Add a warning to the success page for errors
                 //       found here
                 $errors = array();
             }
         }
     }
     // Priorities
     $priorities = $this->getTemplate('priority.yaml')->getData();
     foreach ($priorities as $name => $info) {
         $sql = 'INSERT INTO ' . PRIORITY_TABLE . ' SET priority=' . db_input($name) . ', priority_id=' . db_input($info['priority_id']) . ', priority_desc=' . db_input($info['priority_desc']) . ', priority_color=' . db_input($info['priority_color']) . ', priority_urgency=' . db_input($info['priority_urgency']);
         db_query($sql);
     }
     // Configuration
     require_once INCLUDE_DIR . 'class.config.php';
     if (($tpl = $this->getTemplate('config.yaml')) && ($data = $tpl->getData())) {
         foreach ($data as $section => $items) {
             $_config = new Config($section);
             foreach ($items as $key => $value) {
                 $_config->set($key, $value);
             }
         }
     }
     // Load core config
     $_config = new OsticketConfig();
     // Determine reasonable default max_file_size
     $max_size = Format::filesize2bytes(strtoupper(ini_get('upload_max_filesize')));
     $val = (int) $max_size / 2;
     $po2 = 1;
     while ($po2 < $val) {
         $po2 <<= 1;
     }
     $_config->set('max_file_size', $po2);
     // Pages and content
     foreach (array('landing', 'thank-you', 'offline', 'registration-staff', 'pwreset-staff', 'banner-staff', 'registration-client', 'pwreset-client', 'banner-client', 'registration-confirm', 'registration-thanks', 'access-link') as $type) {
         $tpl = $this->getTemplate("templates/page/{$type}.yaml");
         if (!($page = $tpl->getData())) {
             continue;
         }
         $sql = 'INSERT INTO ' . PAGE_TABLE . ' SET type=' . db_input($type) . ', name=' . db_input($page['name']) . ', body=' . db_input($page['body']) . ', lang=' . db_input($tpl->getLang()) . ', notes=' . db_input($page['notes']) . ', created=NOW(), updated=NOW(), isactive=1';
         if (db_query($sql) && ($id = db_insert_id()) && in_array($type, array('landing', 'thank-you', 'offline'))) {
             $_config->set("{$type}_page_id", $id);
         }
     }
     // Default Language
     $_config->set('system_language', $this->langs[0]);
     // content_id defaults to the `id` field value
     db_query('UPDATE ' . PAGE_TABLE . ' SET content_id=id');
     // Canned response examples
     if (($tpl = $this->getTemplate('templates/premade.yaml')) && ($canned = $tpl->getData())) {
         foreach ($canned as $c) {
             if (($id = Canned::create($c, $errors)) && isset($c['attachments'])) {
                 $premade = Canned::lookup($id);
                 foreach ($c['attachments'] as $a) {
                     $premade->attachments->save($a, false);
                 }
             }
         }
     }
     // Email templates
     // TODO: Lookup tpl_id
     if ($objects = $this->getTemplate('email_template_group.yaml')->getData()) {
         foreach ($objects as $o) {
             $o['lang_id'] = $this->langs[0];
             $tpl = EmailTemplateGroup::create($o, $errors);
         }
     }
     // This shouldn't be necessary
     $tpl = EmailTemplateGroup::lookup(1);
     foreach ($tpl::$all_names as $name => $info) {
         if (($tp = $this->getTemplate("templates/email/{$name}.yaml")) && ($t = $tp->getData())) {
             $t['tpl_id'] = $tpl->getId();
             $t['code_name'] = $name;
             $id = EmailTemplate::create($t, $errors);
             if ($id && ($template = EmailTemplate::lookup($id)) && ($ids = Draft::getAttachmentIds($t['body']))) {
                 $template->attachments->upload($ids, true);
             }
         }
     }
 }
Example #8
0
 function postCannedReply($canned, $msgId, $alert = true)
 {
     global $ost, $cfg;
     if (!is_object($canned) && !($canned = Canned::lookup($canned)) || !$canned->isEnabled()) {
         return false;
     }
     $files = array();
     foreach ($canned->attachments->getAll() as $file) {
         $files[] = $file['id'];
     }
     if ($cfg->isHtmlThreadEnabled()) {
         $response = new HtmlThreadBody($this->replaceVars($canned->getHtml()));
     } else {
         $response = new TextThreadBody($this->replaceVars($canned->getPlainText()));
     }
     $info = array('msgId' => $msgId, 'poster' => __('SYSTEM (Canned Reply)'), 'response' => $response, 'cannedattachments' => $files);
     $errors = array();
     if (!($response = $this->postReply($info, $errors, false, false))) {
         return null;
     }
     $this->markUnAnswered();
     if (!$alert) {
         return $response;
     }
     $dept = $this->getDept();
     if (($email = $dept->getEmail()) && ($tpl = $dept->getTemplate()) && ($msg = $tpl->getAutoReplyMsgTemplate())) {
         if ($dept && $dept->isPublic()) {
             $signature = $dept->getSignature();
         } else {
             $signature = '';
         }
         $msg = $this->replaceVars($msg->asArray(), array('response' => $response, 'signature' => $signature, 'recipient' => $this->getOwner()));
         $attachments = $cfg->emailAttachments() && $files ? $response->getAttachments() : array();
         $options = array('inreplyto' => $response->getEmailMessageId(), 'references' => $response->getEmailReferences(), 'thread' => $response);
         $email->sendAutoReply($this, $msg['subj'], $msg['body'], $attachments, $options);
     }
     return $response;
 }
Example #9
0
 function lookup($id)
 {
     return $id && is_numeric($id) && ($c = new Canned($id)) && $c->getId() == $id ? $c : null;
 }
Example #10
0
 function create($vars, &$errors, $origin, $autorespond = true, $alertstaff = true)
 {
     global $ost, $cfg, $thisclient, $_FILES;
     //Check for 403
     if ($vars['email'] && Validator::is_email($vars['email'])) {
         //Make sure the email address is not banned
         if (EmailFilter::isBanned($vars['email'])) {
             $errors['err'] = 'Ticket denied. Error #403';
             $ost->logWarning('Ticket denied', 'Banned email - ' . $vars['email']);
             return 0;
         }
         //Make sure the open ticket limit hasn't been reached. (LOOP CONTROL)
         if ($cfg->getMaxOpenTickets() > 0 && strcasecmp($origin, 'staff') && ($client = Client::lookupByEmail($vars['email'])) && ($openTickets = $client->getNumOpenTickets()) && $openTickets >= $cfg->getMaxOpenTickets()) {
             $errors['err'] = "You've reached the maximum open tickets allowed.";
             $ost->logWarning('Ticket denied -' . $vars['email'], sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $vars['email']));
             return 0;
         }
     }
     // Make sure email contents should not be rejected
     if (($email_filter = new EmailFilter($vars)) && ($filter = $email_filter->shouldReject())) {
         $errors['err'] = 'Ticket denied. Error #403';
         $ost->logWarning('Ticket denied', sprintf('Banned email - %s by filter "%s"', $vars['email'], $filter->getName()));
         return 0;
     }
     $id = 0;
     $fields = array();
     $fields['name'] = array('type' => 'string', 'required' => 1, 'error' => 'Name required');
     $fields['email'] = array('type' => 'email', 'required' => 1, 'error' => 'Valid email required');
     $fields['subject'] = array('type' => 'string', 'required' => 1, 'error' => 'Subject required');
     $fields['message'] = array('type' => 'text', 'required' => 1, 'error' => 'Message required');
     switch (strtolower($origin)) {
         case 'web':
             $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => 'Select help topic');
             break;
         case 'staff':
             $fields['deptId'] = array('type' => 'int', 'required' => 1, 'error' => 'Dept. required');
             $fields['topicId'] = array('type' => 'int', 'required' => 1, 'error' => 'Topic required');
             $fields['duedate'] = array('type' => 'date', 'required' => 0, 'error' => 'Invalid date - must be MM/DD/YY');
         case 'api':
             $fields['source'] = array('type' => 'string', 'required' => 1, 'error' => 'Indicate source');
             break;
         case 'email':
             $fields['emailId'] = array('type' => 'int', 'required' => 1, 'error' => 'Email unknown');
             break;
         default:
             # TODO: Return error message
             $errors['err'] = $errors['origin'] = 'Invalid origin given';
     }
     $fields['priorityId'] = array('type' => 'int', 'required' => 0, 'error' => 'Invalid Priority');
     $fields['phone'] = array('type' => 'phone', 'required' => 0, 'error' => 'Valid phone # required');
     if (!Validator::process($fields, $vars, $errors) && !$errors['err']) {
         $errors['err'] = 'Missing or invalid data - check the errors and try again';
     }
     //Make sure phone extension is valid
     if ($vars['phone_ext']) {
         if (!is_numeric($vars['phone_ext']) && !$errors['phone']) {
             $errors['phone'] = 'Invalid phone ext.';
         } elseif (!$vars['phone']) {
             //make sure they just didn't enter ext without phone # XXX: reconsider allowing!
             $errors['phone'] = 'Phone number required';
         }
     }
     //Make sure the due date is valid
     if ($vars['duedate']) {
         if (!$vars['time'] || strpos($vars['time'], ':') === false) {
             $errors['time'] = 'Select time';
         } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) === false) {
             $errors['duedate'] = 'Invalid duedate';
         } elseif (strtotime($vars['duedate'] . ' ' . $vars['time']) <= time()) {
             $errors['duedate'] = 'Due date must be in the future';
         }
     }
     # Perform email filter actions on the new ticket arguments XXX: Move filter to the top and check for reject...
     if (!$errors && $email_filter) {
         $email_filter->apply($vars);
     }
     # Some things will need to be unpacked back into the scope of this
     # function
     if (isset($vars['autorespond'])) {
         $autorespond = $vars['autorespond'];
     }
     //Any error above is fatal.
     if ($errors) {
         return 0;
     }
     // OK...just do it.
     $deptId = $vars['deptId'];
     //pre-selected Dept if any.
     $priorityId = $vars['priorityId'];
     $source = ucfirst($vars['source']);
     $topic = NULL;
     // Intenal mapping magic...see if we need to overwrite anything
     if (isset($vars['topicId']) && ($topic = Topic::lookup($vars['topicId']))) {
         //Ticket created via web by user/or staff
         $deptId = $deptId ? $deptId : $topic->getDeptId();
         $priorityId = $priorityId ? $priorityId : $topic->getPriorityId();
         if ($autorespond) {
             $autorespond = $topic->autoRespond();
         }
         $source = $vars['source'] ? $vars['source'] : 'Web';
     } elseif ($vars['emailId'] && !$vars['deptId'] && ($email = Email::lookup($vars['emailId']))) {
         //Emailed Tickets
         $deptId = $email->getDeptId();
         $priorityId = $priorityId ? $priorityId : $email->getPriorityId();
         if ($autorespond) {
             $autorespond = $email->autoRespond();
         }
         $email = null;
         $source = 'Email';
     } elseif ($vars['deptId']) {
         //Opened by staff.
         $deptId = $vars['deptId'];
         $source = ucfirst($vars['source']);
     }
     //Last minute checks
     $priorityId = $priorityId ? $priorityId : $cfg->getDefaultPriorityId();
     $deptId = $deptId ? $deptId : $cfg->getDefaultDeptId();
     $topicId = $vars['topicId'] ? $vars['topicId'] : 0;
     $ipaddress = $vars['ip'] ? $vars['ip'] : $_SERVER['REMOTE_ADDR'];
     //We are ready son...hold on to the rails.
     $extId = Ticket::genExtRandID();
     $sql = 'INSERT INTO ' . TICKET_TABLE . ' SET created=NOW() ' . ' ,lastmessage= NOW()' . ' ,ticketID=' . db_input($extId) . ' ,dept_id=' . db_input($deptId) . ' ,topic_id=' . db_input($topicId) . ' ,priority_id=' . db_input($priorityId) . ' ,email=' . db_input($vars['email']) . ' ,name=' . db_input(Format::striptags($vars['name'])) . ' ,subject=' . db_input(Format::striptags($vars['subject'])) . ' ,phone="' . db_input($vars['phone'], false) . '"' . ' ,phone_ext=' . db_input($vars['phone_ext'] ? $vars['phone_ext'] : '') . ' ,ip_address=' . db_input($ipaddress) . ' ,source=' . db_input($source);
     //Make sure the origin is staff - avoid firebug hack!
     if ($vars['duedate'] && !strcasecmp($origin, 'staff')) {
         $sql .= ' ,duedate=' . db_input(date('Y-m-d G:i', Misc::dbtime($vars['duedate'] . ' ' . $vars['time'])));
     }
     if (!db_query($sql) || !($id = db_insert_id()) || !($ticket = Ticket::lookup($id))) {
         return null;
     }
     /* -------------------- POST CREATE ------------------------ */
     if (!$cfg->useRandomIds()) {
         //Sequential ticketIDs support really..really suck arse.
         $extId = $id;
         //To make things really easy we are going to use autoincrement ticket_id.
         db_query('UPDATE ' . TICKET_TABLE . ' SET ticketID=' . db_input($extId) . ' WHERE ticket_id=' . $id . ' LIMIT 1');
         //TODO: RETHING what happens if this fails?? [At the moment on failure random ID is used...making stuff usable]
     }
     $dept = $ticket->getDept();
     //post the message.
     $msgid = $ticket->postMessage($vars['message'], $source, $vars['mid'], $vars['header'], true);
     // Configure service-level-agreement for this ticket
     $ticket->selectSLAId($vars['slaId']);
     //Auto assign staff or team - auto assignment based on filter rules.
     if ($vars['staffId'] && !$vars['assignId']) {
         $ticket->assignToStaff($vars['staffId'], 'auto-assignment');
     }
     if ($vars['teamId'] && !$vars['assignId']) {
         $ticket->assignToTeam($vars['teamId'], 'auto-assignment');
     }
     /**********   double check auto-response  ************/
     //Overwrite auto responder if the FROM email is one of the internal emails...loop control.
     if ($autorespond && Email::getIdByEmail($ticket->getEmail())) {
         $autorespond = false;
     }
     if ($autorespond && $dept && !$dept->autoRespONNewTicket()) {
         $autorespond = false;
     }
     # Messages that are clearly auto-responses from email systems should
     # not have a return 'ping' message
     if ($autorespond && $vars['header'] && EmailFilter::isAutoResponse(Mail_Parse::splitHeaders($vars['header']))) {
         $autorespond = false;
     }
     //Don't auto respond to mailer daemons.
     if ($autorespond && (strpos(strtolower($vars['email']), 'mailer-daemon@') !== false || strpos(strtolower($vars['email']), 'postmaster@') !== false)) {
         $autorespond = false;
     }
     if ($vars['cannedResponseId'] && ($canned = Canned::lookup($vars['cannedResponseId'])) && $canned->isEnabled()) {
         $files = array();
         foreach ($canned->getAttachments() as $file) {
             $files[] = $file['id'];
         }
         $ticket->postReply(array('msgId' => $msgid, 'response' => $ticket->replaceTemplateVars($canned->getResponse()), 'cannedattachments' => $files), $errors, true);
         // If a canned-response is immediately queued for this ticket,
         // disable the autoresponse
         $autorespond = false;
     }
     /***** See if we need to send some alerts ****/
     $ticket->onNewTicket($vars['message'], $autorespond, $alertstaff);
     /************ check if the user JUST reached the max. open tickets limit **********/
     if ($cfg->getMaxOpenTickets() > 0 && ($client = $ticket->getClient()) && $client->getNumOpenTickets() == $cfg->getMaxOpenTickets()) {
         $ticket->onOpenLimit($autorespond && strcasecmp($origin, 'staff'));
     }
     /* Start tracking ticket lifecycle events */
     $ticket->logEvent('created');
     /* Phew! ... time for tea (KETEPA) */
     return $ticket;
 }
Example #11
0
 function postCannedReply($canned, $msgId, $alert = true)
 {
     global $ost, $cfg;
     if (!is_object($canned) && !($canned = Canned::lookup($canned)) || !$canned->isEnabled()) {
         return false;
     }
     $files = array();
     foreach ($canned->getAttachments() as $file) {
         $files[] = $file['id'];
     }
     $info = array('msgId' => $msgId, 'poster' => 'SYSTEM (Canned Reply)', 'response' => $this->replaceVars($canned->getResponse()), 'cannedattachments' => $files);
     $errors = array();
     if (!($response = $this->postReply($info, $errors, false))) {
         return null;
     }
     $this->markUnAnswered();
     if (!$alert) {
         return $response;
     }
     $dept = $this->getDept();
     if (!($tpl = $dept->getTemplate())) {
         $tpl = $cfg->getDefaultTemplate();
     }
     if (!$dept || !($email = $dept->getEmail())) {
         $email = $cfg->getDefaultEmail();
     }
     if ($tpl && ($msg = $tpl->getAutoReplyMsgTemplate()) && $email) {
         if ($dept && $dept->isPublic()) {
             $signature = $dept->getSignature();
         } else {
             $signature = '';
         }
         $msg = $this->replaceVars($msg->asArray(), array('response' => $response, 'signature' => $signature));
         if ($cfg->stripQuotedReply() && ($tag = $cfg->getReplySeparator())) {
             $msg['body'] = "\n{$tag}\n\n" . $msg['body'];
         }
         $attachments = $cfg->emailAttachments() && $files ? $response->getAttachments() : array();
         $options = array('inreplyto' => $response->getEmailMessageId(), 'references' => $response->getEmailReferences());
         $email->sendAutoReply($this->getEmail(), $msg['subj'], $msg['body'], $attachments, $options);
     }
     return $response;
 }