diff --git a/include/api.tickets.php b/include/api.tickets.php index 1cc51de3f853b1e4dbab206326139c6fd8a0a1cf..9fbbd853658fdd7270d97726864f983f9c611dc5 100644 --- a/include/api.tickets.php +++ b/include/api.tickets.php @@ -12,7 +12,7 @@ class TicketApiController extends ApiController { $supported = array( "alert", "autorespond", "source", "topicId", "attachments" => array("*" => - array("name", "type", "data", "encoding") + array("name", "type", "data", "encoding", "size") ), "message", "ip", "priorityId" ); @@ -53,11 +53,11 @@ class TicketApiController extends ApiController { /* Validate data - overwrites parent's validator for additional validations. */ - function validate(&$data, $format) { + function validate(&$data, $format, $strict=true) { global $ost; //Call parent to Validate the structure - if(!parent::validate($data, $format)) + if(!parent::validate($data, $format, $strict) && $strict) $this->exerr(400, 'Unexpected or invalid data received'); //Nuke attachments IF API files are not allowed. diff --git a/include/class.api.php b/include/class.api.php index 65f0a90e89abaf42ecd5fa980d0b09299b738f3a..68e20c777a8701712299ff8cf5aab482afb24fd3 100644 --- a/include/class.api.php +++ b/include/class.api.php @@ -221,7 +221,7 @@ class ApiController { $this->exerr(400, $parser->lastError()); //Validate structure of the request. - $this->validate($data, $format); + $this->validate($data, $format, false); return $data; } @@ -241,19 +241,25 @@ class ApiController { * expected. It is assumed that the functions actually implementing the * API will further validate the contents of the request */ - function validateRequestStructure($data, $structure, $prefix="") { + function validateRequestStructure($data, $structure, $prefix="", $strict=true) { + global $ost; foreach ($data as $key=>$info) { if (is_array($structure) and is_array($info)) { $search = (isset($structure[$key]) && !is_numeric($key)) ? $key : "*"; if (isset($structure[$search])) { - $this->validateRequestStructure($info, $structure[$search], "$prefix$key/"); + $this->validateRequestStructure($info, $structure[$search], "$prefix$key/", $strict); continue; } } elseif (in_array($key, $structure)) { continue; } - return $this->exerr(400, "$prefix$key: Unexpected data received"); + if ($strict) + return $this->exerr(400, "$prefix$key: Unexpected data received"); + else + $ost->logWarning('API Unexpected Data', + "$prefix$key: Unexpected data received in API request", + false); } return true; @@ -263,11 +269,12 @@ class ApiController { * Validate request. * */ - function validate(&$data, $format) { + function validate(&$data, $format, $strict=true) { return $this->validateRequestStructure( $data, - $this->getRequestStructure($format, $data) - ); + $this->getRequestStructure($format, $data), + "", + $strict); } /** diff --git a/include/class.canned.php b/include/class.canned.php index 96fb712991c3e96d1414c710fb41fece4e13bd0d..457c6d8f904eaaf476bc3744422989f17c940169 100644 --- a/include/class.canned.php +++ b/include/class.canned.php @@ -203,8 +203,8 @@ class Canned { if($errors) return false; $sql=' updated=NOW() '. - ',dept_id='.db_input($vars['dept_id']?$vars['dept_id']:0). - ',isenabled='.db_input($vars['isenabled']?$vars['isenabled']:1). + ',dept_id='.db_input($vars['dept_id']?:0). + ',isenabled='.db_input($vars['isenabled']). ',title='.db_input($vars['title']). ',response='.db_input(Format::sanitize($vars['response'])). ',notes='.db_input(Format::sanitize($vars['notes'])); diff --git a/include/class.config.php b/include/class.config.php index aae5a2a7e8eb8d98bc0a234fbe5b1e4d84d94995..9a02dd480ea92ea3143f693314d48be92cd9136a 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -126,6 +126,15 @@ class Config { return false; return true; } + + function destroy() { + + $sql='DELETE FROM '.$this->table + .' WHERE `'.$this->section_column.'` = '.db_input($this->section); + + db_query($sql); + unset($this->session); + } } class OsticketConfig extends Config { diff --git a/include/class.dept.php b/include/class.dept.php index 0fb59d36faffdbb941275e3f364213062f955b4e..04a0e1b72a43cbd6eaa8ce203698961a0813bfca 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -50,6 +50,7 @@ class Dept { $this->id=$this->ht['dept_id']; $this->email=$this->sla=$this->manager=null; $this->getEmail(); //Auto load email struct. + $this->config = new Config('dept.'.$this->id); $this->members=$this->groups=array(); return true; @@ -99,29 +100,47 @@ class Dept { return count($this->getMembers()); } - function getMembers() { + function getMembers($criteria=null) { - if(!$this->members) { - $this->members = array(); + if(!$this->members || $criteria) { + $members = array(); $sql='SELECT DISTINCT s.staff_id FROM '.STAFF_TABLE.' s ' - .' LEFT JOIN '.GROUP_DEPT_TABLE.' g ON(s.group_id=g.group_id) ' + .' LEFT JOIN '.GROUP_TABLE.' g ON (g.group_id=s.group_id) ' + .' LEFT JOIN '.GROUP_DEPT_TABLE.' gd ON(s.group_id=gd.group_id) ' .' INNER JOIN '.DEPT_TABLE.' d ON(d.dept_id=s.dept_id OR d.manager_id=s.staff_id - OR (d.dept_id=g.dept_id AND d.group_membership=1) + OR (d.dept_id=gd.dept_id AND d.group_membership=1) ) ' - .' WHERE d.dept_id='.db_input($this->getId()) - .' ORDER BY s.lastname, s.firstname'; + .' WHERE d.dept_id='.db_input($this->getId()); + + if ($criteria && $criteria['available']) + $sql .= ' AND + ( g.group_enabled=1 + AND s.isactive=1 + AND s.onvacation=0 ) '; + + $sql.=' ORDER BY s.lastname, s.firstname'; if(($res=db_query($sql)) && db_num_rows($res)) { while(list($id)=db_fetch_row($res)) - $this->members[] = Staff::lookup($id); + $members[$id] = Staff::lookup($id); } + + if ($criteria) + return $members; + + $this->members = $members; + } return $this->members; } + function getAvailableMembers() { + return $this->getMembers(array('available'=>1)); + } + function getSLAId() { return $this->ht['sla_id']; @@ -210,6 +229,9 @@ class Dept { return ($this->ht['noreply_autoresp']); } + function assignMembersOnly() { + return ($this->config->get('assign_members_only', 0)); + } function isGroupMembershipEnabled() { return ($this->ht['group_membership']); @@ -220,11 +242,9 @@ class Dept { } function getInfo() { - return $this->getHashtable(); + return $this->config->getInfo() + $this->getHashtable(); } - - function getAllowedGroups() { if($this->groups) return $this->groups; @@ -240,25 +260,26 @@ class Dept { return $this->groups; } - function updateAllowedGroups($groups) { + function updateSettings($vars) { - if($groups && is_array($groups)) { - foreach($groups as $k=>$id) { + // Groups allowes to access department + if($vars['groups'] && is_array($vars['groups'])) { + foreach($vars['groups'] as $k=>$id) { $sql='INSERT IGNORE INTO '.GROUP_DEPT_TABLE .' SET dept_id='.db_input($this->getId()).', group_id='.db_input($id); db_query($sql); } } - - $sql='DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($this->getId()); - if($groups && is_array($groups)) - $sql.=' AND group_id NOT IN('.implode(',', db_input($groups)).')'; + if($vars['groups'] && is_array($vars['groups'])) + $sql.=' AND group_id NOT IN ('.implode(',', db_input($vars['groups'])).')'; db_query($sql); - return true; + // Misc. config settings + $this->config->set('assign_members_only', $vars['assign_members_only']); + return true; } function update($vars, &$errors) { @@ -266,7 +287,7 @@ class Dept { if(!$this->save($this->getId(), $vars, $errors)) return false; - $this->updateAllowedGroups($vars['groups']); + $this->updateSettings($vars); $this->reload(); return true; @@ -298,6 +319,9 @@ class Dept { //Delete group access db_query('DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($id)); + + // Destrory config settings + $this->config->destroy(); } return $num; @@ -340,6 +364,8 @@ class Dept { if(($manager=$criteria['manager'])) $sql.=' AND manager_id='.db_input(is_object($manager)?$manager->getId():$manager); + $sql.=' ORDER BY dept_name'; + if(($res=db_query($sql)) && db_num_rows($res)) { while(list($id, $name)=db_fetch_row($res)) $depts[$id] = $name; @@ -353,8 +379,12 @@ class Dept { } function create($vars, &$errors) { - if(($id=self::save(0, $vars, $errors)) && ($dept=self::lookup($id))) - $dept->updateAllowedGroups($vars['groups']); + + if(!($id=self::save(0, $vars, $errors))) + return null; + + if (($dept=self::lookup($id))) + $dept->updateSettings($vars); return $id; } @@ -365,13 +395,6 @@ class Dept { if($id && $id!=$vars['id']) $errors['err']='Missing or invalid Dept ID (internal error).'; - if(!isset($vars['id']) - && (!$vars['email_id'] || !is_numeric($vars['email_id']))) - $errors['email_id']='Email selection required'; - - if(isset($vars['tpl_id']) && !is_numeric($vars['tpl_id'])) - $errors['tpl_id']='Template selection required'; - if(!$vars['name']) { $errors['name']='Name required'; } elseif(strlen($vars['name'])<4) { diff --git a/include/class.email.php b/include/class.email.php index 5c0a51c59c1cef1cc7ae0478f83398f2215a0920..efc4a12601250c18c2ef9094e2f34ed5879bf6d9 100644 --- a/include/class.email.php +++ b/include/class.email.php @@ -195,6 +195,15 @@ class Email { } + function __toString() { + + $email = $this->getEmail(); + if ($this->getName()) + $email = sprintf('%s <%s>', $this->getName(), $this->getEmail()); + + return $email; + } + /******* Static functions ************/ function getIdByEmail($email) { diff --git a/include/class.format.php b/include/class.format.php index ac25afb2d01e3fdc6496f632dc66b481046e67ce..14dd88c91a8102ac7d3ab87b8e2a84893b94ba1d 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -384,9 +384,7 @@ class Format { } function stripEmptyLines($string) { - //return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $string); - //return preg_replace('/\s\s+/',"\n",$string); //Too strict?? - return preg_replace("/\n{3,}/", "\n\n", $string); + return preg_replace("/\n{3,}/", "\n\n", trim($string)); } diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 0b739e7c82eeb4a9a1668a096effcbc8ade8616e..4e83c6f4843b78a29bf992a0190e515b1e82e8ff 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -515,15 +515,23 @@ class MailFetcher { return false; } - function getOriginalMessage($mid) { - if (!($body = $this->getPart($mid, 'message/rfc822'))) - return null; + function getOriginalMessageHeaders($mid) { + if (!($body = $this->getPart($mid, 'message/rfc822'))) { + // Handle rfc1892 style bounces + if (!($body = $this->getPart($mid, 'text/rfc822-headers'))) { + return null; + } + else { + // Add a junk body for the parser + $body .= "\n\nIgnored"; + } + } $msg = new Mail_Parse($body); if (!$msg->decode()) return null; - return $msg->struct; + return $msg->struct->headers; } function getPriority($mid) { @@ -619,9 +627,9 @@ class MailFetcher { if ($this->isBounceNotice($mid)) { // Fetch the original References and assign to 'references' - if ($msg = $this->getOriginalMessage($mid)) { - $vars['references'] = $msg->headers['references']; - unset($vars['in-reply-to']); + if ($headers = $this->getOriginalMessageHeaders($mid)) { + $vars['references'] = $headers['references']; + $vars['in-reply-to'] = @$headers['in-reply-to'] ?: null; } // Fetch deliver status report $vars['message'] = $this->getDeliveryStatusMessage($mid); @@ -655,6 +663,7 @@ class MailFetcher { $attachments[] = array( 'cid' => @$at->AttachContentId ?: false, 'data' => $at, + 'size' => @$at->DataSize ?: null, 'type' => @$at->AttachMimeTag ?: false, 'name' => $at->getName(), ); diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 378c68c1959e2a5c6ff4d442a9b8282c43c7aee3..703258b5632f4e835d21c1a7368e70042c76987f 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -32,9 +32,9 @@ class Mail_Parse { var $tnef = false; // TNEF encoded mail - function Mail_parse($mimeMessage, $charset=null){ + function Mail_parse(&$mimeMessage, $charset=null){ - $this->mime_message = $mimeMessage; + $this->mime_message = &$mimeMessage; if($charset) $this->charset = $charset; @@ -54,18 +54,18 @@ class Mail_Parse { $params = array('crlf' => "\r\n", 'charset' => $this->charset, - 'input' => $this->mime_message, 'include_bodies'=> $this->include_bodies, 'decode_headers'=> $this->decode_headers, 'decode_bodies' => $this->decode_bodies); - $this->struct=Mail_mimeDecode::decode($params); + $this->splitBodyHeader(); + + $decoder = new Mail_mimeDecode($this->mime_message); + $this->struct = $decoder->decode($params); if (PEAR::isError($this->struct)) return false; - $this->splitBodyHeader(); - // Handle wrapped emails when forwarded if ($this->struct && $this->struct->parts) { $outer = $this->struct; @@ -119,7 +119,7 @@ class Mail_Parse { function splitBodyHeader() { $match = array(); - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", + if (preg_match("/^(.*?)\r?\n\r?\n./s", $this->mime_message, $match)) { $this->header=$match[1]; @@ -268,11 +268,17 @@ class Mail_Parse { return false; } - function getOriginalMessage() { + function getOriginalMessageHeaders() { foreach ($this->struct->parts as $p) { $ctype = $p->ctype_primary.'/'.$p->ctype_secondary; if (strtolower($ctype) === 'message/rfc822') - return $p->parts[0]; + return $p->parts[0]->headers; + // Handle rfc1892 style bounces + if (strtolower($ctype) === 'text/rfc822-headers') { + $T = new Mail_mimeDecode($p->body . "\n\nIgnored"); + if ($struct = $T->decode()) + return $struct->headers; + } } return null; } @@ -418,6 +424,7 @@ class Mail_Parse { $files[] = array( 'cid' => @$at->AttachContentId ?: false, 'data' => $at->getData(), + 'size' => @$at->DataSize ?: null, 'type' => @$at->AttachMimeTag ?: false, 'name' => $at->getName(), ); @@ -604,8 +611,10 @@ class EmailDataParser { if ($parser->isBounceNotice()) { // Fetch the original References and assign to 'references' - if ($msg = $parser->getOriginalMessage()) - $data['references'] = $msg->headers['references']; + if ($headers = $parser->getOriginalMessageHeaders()) { + $data['references'] = $headers['references']; + $data['in-reply-to'] = @$headers['in-reply-to'] ?: null; + } // Fetch deliver status report $data['message'] = $parser->getDeliveryStatusMessage(); $data['thread-type'] = 'N'; diff --git a/include/class.staff.php b/include/class.staff.php index fac31e542e8f85a65fe35314033b0b589c2e6247..aab9a737b991ecefa6e05597edb16199afe261a4 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -93,12 +93,12 @@ class Staff extends AuthenticatedUser { return $this->__toString(); } - function getHastable() { + function getHashtable() { return $this->ht; } function getInfo() { - return $this->config->getInfo() + $this->getHastable(); + return $this->config->getInfo() + $this->getHashtable(); } // AuthenticatedUser implementation... @@ -585,6 +585,9 @@ class Staff extends AuthenticatedUser { //Cleanup Team membership table. db_query('DELETE FROM '.TEAM_MEMBER_TABLE.' WHERE staff_id='.db_input($this->getId())); + + // Destrory config settings + $this->config->destroy(); } Signal::send('model.deleted', $this); @@ -595,7 +598,7 @@ class Staff extends AuthenticatedUser { /**** Static functions ********/ function getStaffMembers($availableonly=false) { - $sql='SELECT s.staff_id,CONCAT_WS(", ",s.lastname, s.firstname) as name ' + $sql='SELECT s.staff_id, CONCAT_WS(" ", s.firstname, s.lastname) as name ' .' FROM '.STAFF_TABLE.' s '; if($availableonly) { diff --git a/include/class.ticket.php b/include/class.ticket.php index 8102d8de070943206c59328e391806b968074370..4b708707f916268bbb4985c52fcf103f0c2629b0 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -528,11 +528,15 @@ class Ticket { } function getLastMessage() { + if (!isset($this->last_message)) { + if($this->getLastMsgId()) + $this->last_message = Message::lookup( + $this->getLastMsgId(), $this->getId()); - if($this->getLastMsgId()) - return Message::lookup($this->getLastMsgId(), $this->getId()); - - return Message::lastByTicketId($this->getId()); + if (!$this->last_message) + $this->last_message = Message::lastByTicketId($this->getId()); + } + return $this->last_message; } function getThread() { @@ -694,6 +698,10 @@ class Ticket { function setLastMsgId($msgid) { return $this->lastMsgId=$msgid; } + function setLastMessage($message) { + $this->last_message = $message; + $this->setLastMsgId($message->getId()); + } //DeptId can NOT be 0. No orphans please! function setDeptId($deptId) { @@ -855,7 +863,7 @@ class Ticket { //set status to open on a closed ticket. function reopen($isanswered=0) { - $sql='UPDATE '.TICKET_TABLE.' SET updated=NOW(), reopened=NOW() ' + $sql='UPDATE '.TICKET_TABLE.' SET closed=NULL, updated=NOW(), reopened=NOW() ' .' ,status='.db_input('open') .' ,isanswered='.db_input($isanswered) .' WHERE ticket_id='.db_input($this->getId()); @@ -1430,7 +1438,7 @@ class Ticket { if(!is_object($staff) && !($staff=Staff::lookup($staff))) return false; - if(!$this->setStaffId($staff->getId())) + if (!$staff->isAvailable() || !$this->setStaffId($staff->getId())) return false; $this->onAssign($staff, $note, $alert); @@ -1444,7 +1452,7 @@ class Ticket { if(!is_object($team) && !($team=Team::lookup($team))) return false; - if(!$this->setTeamId($team->getId())) + if (!$team->isActive() || !$this->setTeamId($team->getId())) return false; //Clear - staff if it's a closed ticket @@ -1552,7 +1560,7 @@ class Ticket { if(!($message = $this->getThread()->addMessage($vars, $errors))) return null; - $this->setLastMsgId($message->getId()); + $this->setLastMessage($message); //Add email recipients as collaborators... if ($vars['recipients'] @@ -1863,8 +1871,12 @@ class Ticket { $recipients[]=$this->getLastRespondent(); //Assigned staff if any...could be the last respondent - if($cfg->alertAssignedONNewNote() && $this->isAssigned() && $this->getStaffId()) - $recipients[]=$this->getStaff(); + if($cfg->alertAssignedONNewNote() && $this->isAssigned()) { + if ($staff = $this->getStaff()) + $recipients[] = $staff; + if ($team = $this->getTeam()) + $recipients = array_merge($recipients, $team->getMembers()); + } //Dept manager if($cfg->alertDeptManagerONNewNote() && $dept && $dept->getManagerId()) @@ -1878,12 +1890,12 @@ class Ticket { foreach( $recipients as $k=>$staff) { if(!is_object($staff) || !$staff->isAvailable() //Don't bother vacationing staff. - || in_array($staff->getEmail(), $sentlist) //No duplicates. + || isset($sentlist[$staff->getEmail()]) //No duplicates. || $note->getStaffId() == $staff->getId()) //No need to alert the poster! continue; $alert = $this->replaceVars($msg, array('recipient' => $staff)); $email->sendAlert($staff->getEmail(), $alert['subj'], $alert['body'], null, $options); - $sentlist[] = $staff->getEmail(); + $sentlist[$staff->getEmail()] = 1; } } @@ -2620,7 +2632,7 @@ class Ticket { && ($msg=$tpl->getNewTicketNoticeMsgTemplate()) && ($email=$dept->getEmail())) { - $message = $vars['message']; + $message = (string) $ticket->getLastMessage(); if($response) { $message .= ($cfg->isHtmlThreadEnabled()) ? "<br><br>" : "\n\n"; $message .= $response->getBody(); diff --git a/include/class.user.php b/include/class.user.php index 4736a1707633611a18e7935e0422c0865b845faa..21e7d99c0e0955346de6fa043f38b4785ae25a4d 100644 --- a/include/class.user.php +++ b/include/class.user.php @@ -79,6 +79,12 @@ class UserModel extends VerySimpleModel { const PRIMARY_ORG_CONTACT = 0x0001; + static function objects() { + $qs = parent::objects(); + #$qs->select_related('default_email'); + return $qs; + } + function getId() { return $this->id; } @@ -558,6 +564,7 @@ class User extends UserModel { } class PersonsName { + var $format; var $parts; var $name; @@ -574,7 +581,14 @@ class PersonsName { 'original' => array('-- As Entered --', 'getOriginal'), ); - function __construct($name) { + function __construct($name, $format=null) { + global $cfg; + + if ($format && !isset(static::$formats[$format])) + $this->format = $format; + elseif($cfg) + $this->format = $cfg->getDefaultNameFormat(); + $this->parts = static::splitName($name); $this->name = $name; } @@ -663,10 +677,10 @@ class PersonsName { } function __toString() { - global $cfg; - $format = $cfg ? $cfg->getDefaultNameFormat() : 'original'; - list(,$func) = static::$formats[$format]; + + @list(, $func) = static::$formats[$this->format]; if (!$func) $func = 'getFull'; + return (string) call_user_func(array($this, $func)); } diff --git a/include/client/open.inc.php b/include/client/open.inc.php index 3f070c703d9c32b63fc43ca1f3001aff0207f546..26d146f22cd250589622ecea45d612847ecc239d 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -71,7 +71,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$info; <td> <span class="captcha"><img src="captcha.php" border="0" align="left"></span> - <input id="captcha" type="text" name="captcha" size="6"> + <input id="captcha" type="text" name="captcha" size="6" autocomplete="off"> <em>Enter the text shown on the image.</em> <font class="error">* <?php echo $errors['captcha']; ?></font> </td> diff --git a/include/i18n/en_US/department.yaml b/include/i18n/en_US/department.yaml index 05ffc9d9ca54c86a5865bd2d317f561c0ced81a0..3de7de70b6a2965679f39a870e80460516d04206 100644 --- a/include/i18n/en_US/department.yaml +++ b/include/i18n/en_US/department.yaml @@ -17,6 +17,7 @@ signature: | Support Department ispublic: 1 + group_membership: 1 - id: 2 name: Sales @@ -24,9 +25,11 @@ Sales and Customer Retention ispublic: 1 sla_id: 1 + group_membership: 1 - id: 3 name: Maintenance signature: | Maintenance Department ispublic: 0 + group_membership: 0 diff --git a/include/i18n/en_US/help/tips/settings.alerts.yaml b/include/i18n/en_US/help/tips/settings.alerts.yaml index a085c8c0171f7ae44cb46dc377735f0eb049a147..d13a702e51d84ad887c7ff2a99fb38b1eb777729 100644 --- a/include/i18n/en_US/help/tips/settings.alerts.yaml +++ b/include/i18n/en_US/help/tips/settings.alerts.yaml @@ -26,8 +26,7 @@ new_ticket_alert: title: New Ticket Alert content: > <p> - Pertains to alerts that are sent out when new tickets are created by - Clients. + Pertains to alerts that are sent out when new tickets are created. </p><p class="info-banner"> <i class="icon-info-sign"></i> Staff members (department members) are not diff --git a/include/i18n/en_US/templates/email/ticket.autoresp.yaml b/include/i18n/en_US/templates/email/ticket.autoresp.yaml index 6b1826e9e4cfc8201499da64422fc1004b3b1d63..d40ba578a08b6d500f4d28af47e89930c2df973e 100644 --- a/include/i18n/en_US/templates/email/ticket.autoresp.yaml +++ b/include/i18n/en_US/templates/email/ticket.autoresp.yaml @@ -11,21 +11,12 @@ subject: | Support Ticket Opened [#%{ticket.number}] body: | <h3><strong>Dear %{recipient.name.first},</strong></h3> - Our customer care team has created a ticket, - <a href="%{recipient.ticket_link}">#%{ticket.number}</a> on your behalf, - with the following details and summary: <br> - <br> - Subject: <strong>%{ticket.subject}</strong><br> - Submitted: <strong>%{ticket.create_date}</strong> - <br> - <br> - %{message} - <br> - <br> + <p> + A request for support has been created and assigned #%{ticket.number}. A representative will follow-up with you as soon as possible. You can <a href="%{recipient.ticket_link}">view this ticket's progress online</a>. - <br> + </p> <br> <div style="color: rgb(127, 127, 127)"> Your %{company.name} Team, diff --git a/include/pear/Mail/mimeDecode.php b/include/pear/Mail/mimeDecode.php index b300195824c30528f7ff44987679fd11875889e3..bc524f0cc2cbc8abd75d4c26dcb06201cbd1b98e 100644 --- a/include/pear/Mail/mimeDecode.php +++ b/include/pear/Mail/mimeDecode.php @@ -91,14 +91,6 @@ require_once 'PEAR.php'; */ class Mail_mimeDecode extends PEAR { - /** - * The raw email to decode - * - * @var string - * @access private - */ - var $_input; - /** * The header part of the input * @@ -157,13 +149,13 @@ class Mail_mimeDecode extends PEAR * @param string The input to decode * @access public */ - function Mail_mimeDecode($input) + function Mail_mimeDecode(&$input) { list($header, $body) = $this->_splitBodyHeader($input); - $this->_input = $input; - $this->_header = $header; - $this->_body = $body; + $this->_input = &$input; + $this->_header = &$header; + $this->_body = &$body; $this->_decode_bodies = false; $this->_include_bodies = true; } @@ -241,7 +233,7 @@ class Mail_mimeDecode extends PEAR * @return object Results of decoding process * @access private */ - function _decode($headers, $body, $default_ctype = 'text/plain') + function _decode(&$headers, &$body, $default_ctype = 'text/plain') { $return = new stdClass; $return->headers = array(); @@ -324,8 +316,9 @@ class Mail_mimeDecode extends PEAR $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); - for ($i = 0; $i < count($parts); $i++) { - list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); + while (count($parts)) { + $part = array_shift($parts); + list($part_header, $part_body) = $this->_splitBodyHeader($part); $part = $this->_decode($part_header, $part_body, $default_ctype); if($part === false) $part = $this->raiseError($this->_error); @@ -409,10 +402,18 @@ class Mail_mimeDecode extends PEAR * @return array Contains header and body section * @access private */ - function _splitBodyHeader($input) + function _splitBodyHeader(&$input) { - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { - return array($match[1], $match[2]); + if ($input instanceof StringView) + $check = $input->substr(0, 64<<10); + else + $check = &$input; + if (preg_match("/^.*?(\r?\n\r?\n)(.)/s", $check, $match, PREG_OFFSET_CAPTURE)) { + $headers = ($input instanceof StringView) + ? (string) $input->substr(0, $match[1][1]) : substr($input, 0, $match[1][1]); + $body = ($input instanceof StringView) + ? $input->substr($match[2][1]) : new StringView($input, $match[2][1]); + return array($headers, $body); } $this->_error = 'Could not split header and body'; return false; @@ -524,6 +525,12 @@ class Mail_mimeDecode extends PEAR $boundary = $bs_possible; } + if ($input instanceof StringView) { + $parts = $input->split('--' . $boundary); + array_shift($parts); + return $parts; + } + $tmp = explode('--' . $boundary, $input); for ($i = 1; $i < count($tmp) - 1; $i++) { @@ -871,3 +878,51 @@ class Mail_mimeDecode extends PEAR } } // End of class + +class StringView { + var $string; + var $start; + var $end; + + function __construct(&$string, $start=0, $end=false) { + $this->string = &$string; + $this->start = $start; + $this->end = $end; + } + + function __toString() { + return $this->end + ? substr($this->string, $this->start, $this->end - $this->start) + : substr($this->string, $this->start); + } + + function substr($start, $end=false) { + return new StringView($this->string, $this->start + $start, + $end ? min($this->start + $end, $this->end ?: PHP_INT_MAX) : $this->end); + } + + function split($token) { + $ltoken = strlen($token); + $windows = array(); + $offset = $this->start; + for ($i = 0;; $i++) { + $windows[$i] = array('start' => $offset); + $offset = strpos($this->string, $token, $offset); + if (!$offset || ($this->end && $offset >= $this->end)) + break; + + // Enforce local window + $windows[$i]['stop'] = min($this->end ?: $offset, $offset); + $offset += $ltoken; + if ($this->end && $offset > $this->end) + break; + } + + $parts = array(); + foreach ($windows as $w) { + $parts[] = new static($this->string, $w['start'], @$w['stop'] ?: false); + } + return $parts; + + } +} diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index 3a771fb0b46575ee9346d16788be809327de741a..84b4cf4ede75d14b11316cbd8eeb10419e4355a9 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -19,6 +19,9 @@ if($dept && $_REQUEST['a']!='add') { $info['ispublic']=isset($info['ispublic'])?$info['ispublic']:1; $info['ticket_auto_response']=isset($info['ticket_auto_response'])?$info['ticket_auto_response']:1; $info['message_auto_response']=isset($info['message_auto_response'])?$info['message_auto_response']:1; + if (!isset($info['group_membership'])) + $info['group_membership'] = 1; + $qstr.='&a='.$_REQUEST['a']; } $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); @@ -59,49 +62,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </td> </tr> <tr> - <td width="180" class="required"> - Email: - </td> - <td> - <select name="email_id"> - <option value="0">— Select Department Email —</option> - <?php - $sql='SELECT email_id,email,name FROM '.EMAIL_TABLE.' email ORDER by name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while(list($id,$email,$name)=db_fetch_row($res)){ - $selected=($info['email_id'] && $id==$info['email_id'])?'selected="selected"':''; - if($name) - $email=Format::htmlchars("$name <$email>"); - echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$email); - } - } - ?> - </select> - <span class="error">* <?php echo $errors['email_id']; ?></span> <i class="help-tip icon-question-sign" href="#email"></i> - </td> - </tr> - <tr> - <td width="180" class="required"> - Template: - </td> - <td> - <select name="tpl_id"> - <option value="0">— System Default —</option> - <?php - $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_GRP_TABLE.' tpl WHERE isactive=1 ORDER by name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while(list($id,$name)=db_fetch_row($res)){ - $selected=($info['tpl_id'] && $id==$info['tpl_id'])?'selected="selected"':''; - echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); - } - } - ?> - </select> - <span class="error">* <?php echo $errors['tpl_id']; ?></span> <i class="help-tip icon-question-sign" href="#template"></i> - </td> - </tr> - <tr> - <td width="180" class="required"> + <td width="180"> SLA: </td> <td> @@ -120,7 +81,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </td> </tr> <tr> - <td width="180" class="required"> + <td width="180"> Manager: </td> <td> @@ -150,9 +111,67 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Extend membership to groups with access. <i>(Alerts and notices will include groups)</i> <i class="help-tip icon-question-sign" href="#group_membership"></i> </td> </tr> + <tr> + <td>Ticket Assignment:</td> + <td> + <input type="checkbox" name="assign_members_only" <?php echo + $info['assign_members_only']?'checked="checked"':''; ?>> + Limit ticket assignment to department members + <!-- Help Tip: + Tickets can ONLY be assigned to department members (+ group members)--> + </td> + </tr> + <tr> + <th colspan="2"> + <em><strong>Outgoing Email Settings</strong>:</em> + </th> + </tr> + <tr> + <td width="180"> + Outgoing Email: + </td> + <td> + <select name="email_id"> + <option value="0">— System Default —</option> + <?php + $sql='SELECT email_id,email,name FROM '.EMAIL_TABLE.' email ORDER by name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id,$email,$name)=db_fetch_row($res)){ + $selected=($info['email_id'] && $id==$info['email_id'])?'selected="selected"':''; + if($name) + $email=Format::htmlchars("$name <$email>"); + echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$email); + } + } + ?> + </select> + <span class="error"> <?php echo $errors['email_id']; ?></span> <i class="help-tip icon-question-sign" href="#email"></i> + </td> + </tr> + <tr> + <td width="180"> + Template Set: + </td> + <td> + <select name="tpl_id"> + <option value="0">— System Default —</option> + <?php + $sql='SELECT tpl_id,name FROM '.EMAIL_TEMPLATE_GRP_TABLE.' tpl WHERE isactive=1 ORDER by name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id,$name)=db_fetch_row($res)){ + $selected=($info['tpl_id'] && $id==$info['tpl_id'])?'selected="selected"':''; + echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); + } + } + ?> + </select> + <span class="error"> <?php echo $errors['tpl_id']; ?></span> <i class="help-tip icon-question-sign" href="#template"></i> + </td> + </tr> <tr> <th colspan="2"> - <em><strong>Auto Response Settings</strong>: Override global auto-response settings for tickets routed to the Dept. <i class="help-tip icon-question-sign" href="#auto_response_settings"></i></em> + <em><strong>Autoresponder Settings</strong>: Override global auto-response settings for tickets routed to the department. + <i class="help-tip icon-question-sign" href="#auto_response_settings"></i></em> </th> </tr> <tr> diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php index 23d6937e8c1f474997250370e4d0bd453f58771d..da9c74c5e3e3c3e3e38060e352eb4700b4812f34 100644 --- a/include/staff/departments.inc.php +++ b/include/staff/departments.inc.php @@ -54,7 +54,7 @@ else <caption><?php echo $showing; ?></caption> <thead> <tr> - <th width="7px"> </th> + <th width="7px"> </th> <th width="180"><a <?php echo $name_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=name">Name</a></th> <th width="80"><a <?php echo $type_sort; ?> href="departments.php?<?php echo $qstr; ?>&sort=type">Type</a></th> <th width="70"><a <?php echo $users_sort; ?>href="departments.php?<?php echo $qstr; ?>&sort=users">Users</a></th> @@ -68,17 +68,25 @@ else $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; if($res && db_num_rows($res)): $defaultId=$cfg->getDefaultDeptId(); + $defaultEmailId = $cfg->getDefaultEmail()->getId(); + $defaultEmailAddress = (string) $cfg->getDefaultEmail(); while ($row = db_fetch_array($res)) { $sel=false; if($ids && in_array($row['dept_id'],$ids)) $sel=true; - - $row['email']=$row['email_name']?($row['email_name'].' <'.$row['email'].'>'):$row['email']; + + if ($row['email_id']) + $row['email']=$row['email_name']?($row['email_name'].' <'.$row['email'].'>'):$row['email']; + elseif($defaultEmailId) { + $row['email_id'] = $defaultEmailId; + $row['email'] = $defaultEmailAddress; + } + $default=($defaultId==$row['dept_id'])?' <small>(Default)</small>':''; ?> <tr id="<?php echo $row['dept_id']; ?>"> <td width=7px> - <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['dept_id']; ?>" + <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['dept_id']; ?>" <?php echo $sel?'checked="checked"':''; ?> <?php echo $default?'disabled="disabled"':''; ?> > </td> <td><a href="departments.php?id=<?php echo $row['dept_id']; ?>"><?php echo $row['dept_name']; ?></a> <?php echo $default; ?></td> @@ -91,7 +99,8 @@ else <?php } ?> </b> </td> - <td><a href="emails.php?id=<?php echo $row['email_id']; ?>"><?php echo $row['email']; ?></a></td> + <td><a href="emails.php?id=<?php echo $row['email_id']; ?>"><?php + echo Format::htmlchars($row['email']); ?></a> </td> <td><a href="staff.php?id=<?php echo $row['manager_id']; ?>"><?php echo $row['manager']; ?> </a></td> </tr> <?php diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index a1b92945c6cc52279d8cd1219f59560b6b745b6f..dce774dca55109b58de4616b7f83abc28ca24a2d 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -197,13 +197,16 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="canned_response_id"> <option value="">— None —</option> <?php - $sql='SELECT canned_id,title FROM '.CANNED_TABLE - .' WHERE isenabled ORDER by title'; + $sql='SELECT canned_id, title, isenabled FROM '.CANNED_TABLE .' ORDER by title'; if ($res=db_query($sql)) { - while (list($id,$title)=db_fetch_row($res)) { + while (list($id, $title, $isenabled)=db_fetch_row($res)) { $selected=($info['canned_response_id'] && $id==$info['canned_response_id']) ? 'selected="selected"' : ''; + + if (!$isenabled) + $title .= ' (disabled)'; + echo sprintf('<option value="%d" %s>%s</option>', $id, $selected, $title); } @@ -281,32 +284,27 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <td> <select name="assign"> <option value="0">— Unassigned —</option> - - <?php - - - $sql=' SELECT staff_id,CONCAT_WS(", ",lastname,firstname) as name '. - ' FROM '.STAFF_TABLE.' WHERE isactive=1 ORDER BY name'; - - if(($res=db_query($sql)) && db_num_rows($res)){ + if (($users=Staff::getStaffMembers())) { echo '<OPTGROUP label="Staff Members">'; - while (list($id,$name) = db_fetch_row($res)){ + foreach($users as $id => $name) { + $name = new PersonsName($name); $k="s$id"; $selected = ($info['assign']==$k || $info['staff_id']==$id)?'selected="selected"':''; ?> <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> - - <?php } + <?php + } echo '</OPTGROUP>'; - } - $sql='SELECT team_id, name FROM '.TEAM_TABLE.' WHERE isenabled=1'; + $sql='SELECT team_id, isenabled, name FROM '.TEAM_TABLE .' ORDER BY name'; if(($res=db_query($sql)) && db_num_rows($res)){ echo '<OPTGROUP label="Teams">'; - while (list($id,$name) = db_fetch_row($res)){ + while (list($id, $isenabled, $name) = db_fetch_row($res)){ $k="t$id"; $selected = ($info['assign']==$k || $info['team_id']==$id)?'selected="selected"':''; + if (!$isenabled) + $name .= ' (disabled)'; ?> <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> <?php diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index d0e6e9cf6fea46d528c0ddb4d6a5fd56f456913f..44de81e20e739a1a8ee868d6e7b4a811d12b7c5e 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -193,25 +193,28 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <select name="assign"> <option value="0">— Unassigned —</option> <?php - $sql=' SELECT staff_id,CONCAT_WS(", ",lastname,firstname) as name '. - ' FROM '.STAFF_TABLE.' WHERE isactive=1 ORDER BY name'; - if(($res=db_query($sql)) && db_num_rows($res)){ + if (($users=Staff::getStaffMembers())) { echo '<OPTGROUP label="Staff Members">'; - while (list($id,$name) = db_fetch_row($res)){ + foreach ($users as $id => $name) { + $name = new PersonsName($name); $k="s$id"; $selected = ($info['assign']==$k || $info['staff_id']==$id)?'selected="selected"':''; ?> <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> - <?php } + <?php + } echo '</OPTGROUP>'; } - $sql='SELECT team_id, name FROM '.TEAM_TABLE.' WHERE isenabled=1'; + $sql='SELECT team_id, name, isenabled FROM '.TEAM_TABLE.' ORDER BY name'; if(($res=db_query($sql)) && db_num_rows($res)){ echo '<OPTGROUP label="Teams">'; - while (list($id,$name) = db_fetch_row($res)){ + while (list($id, $name, $isenabled) = db_fetch_row($res)){ $k="t$id"; $selected = ($info['assign']==$k || $info['team_id']==$id)?'selected="selected"':''; + + if (!$isenabled) + $name .= ' (disabled)'; ?> <option value="<?php echo $k; ?>"<?php echo $selected; ?>><?php echo $name; ?></option> <?php diff --git a/include/staff/settings-alerts.inc.php b/include/staff/settings-alerts.inc.php index 2f60d79689c3186f985dc26c5752218ad7296eb0..4613a0bf2837e4f379f3966846cb283ec374cb5f 100644 --- a/include/staff/settings-alerts.inc.php +++ b/include/staff/settings-alerts.inc.php @@ -89,7 +89,7 @@ </tr> <tr> <td> - <input type="checkbox" name="note_alert_assigned" <?php echo $config['note_alert_assigned']?'checked':''; ?>> Assigned Staff <i class="help-tip icon-question-sign" href="#assigned_staff_2"></i> + <input type="checkbox" name="note_alert_assigned" <?php echo $config['note_alert_assigned']?'checked':''; ?>> Assigned Staff / Team Members<i class="help-tip icon-question-sign" href="#assigned_staff_2"></i> </td> </tr> <tr> diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php index 899e11a0a39356e0bbddd18dea047e319635fe1c..7549453fe690c65acd51268da334d5e3df7a1ca9 100644 --- a/include/staff/slaplan.inc.php +++ b/include/staff/slaplan.inc.php @@ -62,16 +62,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <td> <input type="radio" name="isactive" value="1" <?php echo $info['isactive']?'checked="checked"':''; ?>><strong>Active</strong> <input type="radio" name="isactive" value="0" <?php echo !$info['isactive']?'checked="checked"':''; ?>>Disabled - <span class="error">* </span> - </td> - </tr> - <tr> - <td width="180"> - Priority Escalation: - </td> - <td> - <input type="checkbox" name="enable_priority_escalation" value="1" <?php echo $info['enable_priority_escalation']?'checked="checked"':''; ?> > - <strong>Enable</strong> priority escalation on overdue tickets. <i class="help-tip icon-question-sign" href="#priority_escalation"></i> + <span class="error">* <?php echo $errors['isactive']; ?></span> </td> </tr> <tr> diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 04566aee31bffdab2f5dc2e4b8cf3ddedfc3722e..ff6fa6abe5601bbbf84be2d35b8697b8c753e5f6 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -53,7 +53,7 @@ else <caption><?php echo $showing; ?></caption> <thead> <tr> - <th width="7"> </th> + <th width="7"> </th> <th width="320"><a <?php echo $name_sort; ?> href="slas.php?<?php echo $qstr; ?>&sort=name">Name</a></th> <th width="100"><a <?php echo $status_sort; ?> href="slas.php?<?php echo $qstr; ?>&sort=status">Status</a></th> <th width="130"><a <?php echo $period_sort; ?> href="slas.php?<?php echo $qstr; ?>&sort=period">Grace Period (hrs)</a></th> @@ -66,17 +66,24 @@ else $total=0; $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; if($res && db_num_rows($res)): + $defaultId = $cfg->getDefaultSLAId(); while ($row = db_fetch_array($res)) { $sel=false; if($ids && in_array($row['id'],$ids)) $sel=true; + + $default = ''; + if ($row['id'] == $defaultId) + $default = '<small><em>(Default)</em></small>'; ?> <tr id="<?php echo $row['id']; ?>"> <td width=7px> - <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['id']; ?>" - <?php echo $sel?'checked="checked"':''; ?>> + <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['id']; ?>" + <?php echo $sel?'checked="checked"':''; ?>> </td> - <td> <a href="slas.php?id=<?php echo $row['id']; ?>"><?php echo Format::htmlchars($row['name']); ?></a></td> + <td> <a href="slas.php?id=<?php echo $row['id']; + ?>"><?php echo Format::htmlchars($row['name']); + ?></a> <?php echo $default; ?></td> <td><?php echo $row['isactive']?'Active':'<b>Disabled</b>'; ?></td> <td style="text-align:right;padding-right:35px;"><?php echo $row['grace_period']; ?> </td> <td> <?php echo Format::db_date($row['created']); ?></td> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 47df3fe47726500f22aa360def7262c960616c83..ed2f5bab5ee98ec05ba9efe26a662098537eb2c6 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -816,16 +816,25 @@ $tcount+= $ticket->getNumNotes(); echo sprintf('<option value="%d">Claim Ticket (comments optional)</option>', $thisstaff->getId()); $sid=$tid=0; - if(($users=Staff::getAvailableStaffMembers())) { + + if ($dept->assignMembersOnly()) + $users = $dept->getAvailableMembers(); + else + $users = Staff::getAvailableStaffMembers(); + + if ($users) { echo '<OPTGROUP label="Staff Members ('.count($users).')">'; $staffId=$ticket->isAssigned()?$ticket->getStaffId():0; foreach($users as $id => $name) { if($staffId && $staffId==$id) continue; + if (!is_object($name)) + $name = new PersonsName($name); + $k="s$id"; echo sprintf('<option value="%s" %s>%s</option>', - $k,(($info['assignId']==$k)?'selected="selected"':''),$name); + $k,(($info['assignId']==$k)?'selected="selected"':''), $name); } echo '</OPTGROUP>'; } diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index b63d16a31c4ec0028bf1533614e32e3b3522e579..88cb3898018e96e5e4c5dd609d16a3216a65e640 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -229,7 +229,7 @@ $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&ord //ADD attachment,priorities, lock and other crap $qselect.=' ,IF(ticket.duedate IS NULL,IF(sla.id IS NULL, NULL, DATE_ADD(ticket.created, INTERVAL sla.grace_period HOUR)), ticket.duedate) as duedate ' - .' ,CAST(GREATEST(IFNULL(ticket.lastmessage, 0), IFNULL(ticket.reopened, 0), ticket.created) as datetime) as effective_date ' + .' ,CAST(GREATEST(IFNULL(ticket.lastmessage, 0), IFNULL(ticket.closed, 0), IFNULL(ticket.reopened, 0), ticket.created) as datetime) as effective_date ' .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team ' .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned ' .' ,IF(ptopic.topic_pid IS NULL, topic.topic, CONCAT_WS(" / ", ptopic.topic, topic.topic)) as helptopic ' diff --git a/include/tnef_decoder.php b/include/tnef_decoder.php index 45ee5b5c074db014d98e69af2c2238697c550820..e0f7869ba82b4ce554ada486efbfb1ae9cc4bb67 100644 --- a/include/tnef_decoder.php +++ b/include/tnef_decoder.php @@ -491,6 +491,7 @@ class TnefStreamParser { break; case self::attAttachData: $attach->_setData($info['data']); + $attach->_setDataSize($info['length']); break; } } @@ -557,6 +558,10 @@ class TnefAttachment extends AbstractTnefObject { $this->Data = $data; } + function _setDataSize($size) { + $this->DataSize = $size; + } + function getData() { if (isset($this->Data)) return $this->Data; diff --git a/scp/slas.php b/scp/slas.php index 03368fbaabea19a1aace6acac893219e782e516b..7003be1c9d86ce5e70fa7eddf04dcb8a8fcfef0d 100644 --- a/scp/slas.php +++ b/scp/slas.php @@ -73,7 +73,9 @@ if($_POST){ case 'delete': $i=0; foreach($_POST['ids'] as $k=>$v) { - if(($p=SLA::lookup($v)) && $p->delete()) + if (($p=SLA::lookup($v)) + && $p->getId() != $cfg->getDefaultSLAId() + && $p->delete()) $i++; } diff --git a/setup/inc/class.installer.php b/setup/inc/class.installer.php index 2f56574be91f858c2dcffe57bd0af6012e282038..31213d4c678fcaacc6f720fc42652727d4e0be00 100644 --- a/setup/inc/class.installer.php +++ b/setup/inc/class.installer.php @@ -248,9 +248,6 @@ class Installer extends SetupWizard { $sql='UPDATE '.PREFIX."email SET dept_id=$dept_id_1"; db_query($sql, false); - $sql='UPDATE '.PREFIX."department SET email_id=$support_email_id" - .", autoresp_email_id=$support_email_id"; - db_query($sql, false); global $cfg; $cfg = new OsticketConfig();