diff --git a/include/api.tickets.php b/include/api.tickets.php index 55dc5cf1ea6ceccd93a54fb51e7a5467ff7c6991..7268d0ffabaacedf3707c9a50071a955b17809e0 100644 --- a/include/api.tickets.php +++ b/include/api.tickets.php @@ -72,6 +72,15 @@ class TicketApiController extends ApiController { if(!($attachment['data'] = base64_decode($attachment['data'], true))) $attachment['error'] = sprintf('%s: Poorly encoded base64 data', Format::htmlchars($attachment['name'])); } + if (!$attachment['error'] + && ($size = $ost->getConfig()->getMaxFileSize()) + && ($fsize = $attachment['size'] ?: strlen($attachment['data'])) + && $fsize > $size) { + $attachment['error'] = sprintf('File %s (%s) is too big. Maximum of %s allowed', + Format::htmlchars($attachment['name']), + Format::file_size($fsize), + Format::file_size($size)); + } } unset($attachment); } diff --git a/include/class.mailer.php b/include/class.mailer.php index c80421fcb798e51b2aa7011c902e78f9d6e30615..1c43398bcf4d3af04540fdbe6c01fbc181d2f2e2 100644 --- a/include/class.mailer.php +++ b/include/class.mailer.php @@ -206,21 +206,38 @@ class Mailer { $body = $mime->get($encodings); //encode the headers. $headers = $mime->headers($headers, true); + + // Cache smtp connections made during this request + static $smtp_connections = array(); if(($smtp=$this->getSMTPInfo())) { //Send via SMTP - $mail = mail::factory('smtp', - array ('host' => $smtp['host'], - 'port' => $smtp['port'], - 'auth' => $smtp['auth'], - 'username' => $smtp['username'], - 'password' => $smtp['password'], - 'timeout' => 20, - 'debug' => false, - )); + $key = sprintf("%s:%s:%s", $smtp['host'], $smtp['port'], + $smtp['username']); + if (!isset($smtp_connections[$key])) { + $mail = mail::factory('smtp', array( + 'host' => $smtp['host'], + 'port' => $smtp['port'], + 'auth' => $smtp['auth'], + 'username' => $smtp['username'], + 'password' => $smtp['password'], + 'timeout' => 20, + 'debug' => false, + 'persist' => true, + )); + if ($mail->connect()) + $smtp_connections[$key] = $mail; + } + else { + // Use persistent connection + $mail = $smtp_connections[$key]; + } $result = $mail->send($to, $headers, $body); if(!PEAR::isError($result)) return $messageId; + // Force reconnect on next ->send() + unset($smtp_connections[$key]); + $alert=sprintf("Unable to email via SMTP:%s:%d [%s]\n\n%s\n", $smtp['host'], $smtp['port'], $smtp['username'], $result->getMessage()); $this->logError($alert); diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 0c24fa72cfa1ee11b27a16c25f908692b2b8d2b8..73ac6184521639c58142324c269127d185b51c0f 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -20,6 +20,7 @@ require_once(INCLUDE_DIR.'class.dept.php'); require_once(INCLUDE_DIR.'class.email.php'); require_once(INCLUDE_DIR.'class.filter.php'); require_once(INCLUDE_DIR.'html2text.php'); +require_once(INCLUDE_DIR.'tnef_decoder.php'); class MailFetcher { @@ -30,6 +31,8 @@ class MailFetcher { var $charset = 'UTF-8'; + var $tnef = false; + function MailFetcher($email, $charset='UTF-8') { @@ -290,10 +293,21 @@ class MailFetcher { if($headerinfo->cc) $tolist['cc'] = $headerinfo->cc; + //Add delivered-to address to list. + if (stripos($header['header'], 'delivered-to:') !==false + && ($dt = Mail_Parse::findHeaderEntry($header['header'], + 'delivered-to', true))) { + if (($delivered_to = Mail_Parse::parseAddressList($dt))) + $tolist['delivered-to'] = $delivered_to; + } + $header['recipients'] = array(); foreach($tolist as $source => $list) { foreach($list as $addr) { - if(!($emailId=Email::getIdByEmail(strtolower($addr->mailbox).'@'.$addr->host))) { + if (!($emailId=Email::getIdByEmail(strtolower($addr->mailbox).'@'.$addr->host))) { + //Skip virtual Delivered-To addresses + if ($source == 'delivered-to') continue; + $header['recipients'][] = array( 'source' => "Email ($source)", 'name' => $this->mime_decode(@$addr->personal), @@ -304,6 +318,16 @@ class MailFetcher { } } + //See if any of the recipients is a delivered to address + if ($tolist['delivered-to']) { + foreach ($tolist['delivered-to'] as $addr) { + foreach ($header['recipients'] as $i => $r) { + if (strcasecmp($r['email'], $addr->mailbox.'@'.$addr->host) === 0) + $header['recipients'][$i]['source'] = 'delivered-to'; + } + } + } + //BCCed? if(!$header['emailId']) { if ($headerinfo->bcc) { @@ -356,6 +380,10 @@ class MailFetcher { } } + if ($this->tnef && !strcasecmp($mimeType, 'text/html') + && ($content = $this->tnef->getBody('text/html', $encoding))) + return $content; + //Do recursive search $text=''; if($struct && $struct->parts && $recurse) { @@ -491,6 +519,10 @@ class MailFetcher { } function getPriority($mid) { + if ($this->tnef && isset($this->tnef->Importance)) + // PidTagImportance is 0, 1, or 2 + // http://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx + return $this->tnef->Importance + 1; return Mail_Parse::parsePriority($this->getHeader($mid)); } @@ -549,6 +581,23 @@ class MailFetcher { return true; //Report success (moved or delete) } + // Parse MS TNEF emails + if (($struct = imap_fetchstructure($this->mbox, $mid)) + && ($attachments = $this->getAttachments($struct))) { + foreach ($attachments as $i=>$info) { + if (0 === strcasecmp('application/ms-tnef', $info['type'])) { + $data = $this->decode(imap_fetchbody($self->mbox, + $mid, $info['index']), $info['encoding']); + $tnef = new TnefStreamParser($data); + $this->tnef = $tnef->getMessage(); + // No longer considered an attachment + unset($attachments[$i]); + // There should only be one of these + break; + } + } + } + $vars = $mailinfo; $vars['name'] = $mailinfo['name']; $vars['subject'] = $mailinfo['subject'] ? $mailinfo['subject'] : '[No Subject]'; @@ -583,10 +632,18 @@ class MailFetcher { $seen = false; // Fetch attachments if any. - if($ost->getConfig()->allowEmailAttachments() - && ($struct = imap_fetchstructure($this->mbox, $mid)) - && ($attachments=$this->getAttachments($struct))) { - + if($ost->getConfig()->allowEmailAttachments()) { + // Include TNEF attachments in the attachments list + if ($this->tnef) { + foreach ($this->tnef->attachments as $at) { + $attachments[] = array( + 'cid' => @$at->AttachContentId ?: false, + 'data' => $at->Data, + 'type' => @$at->AttachMimeTag ?: false, + 'name' => $at->getName(), + ); + } + } $vars['attachments'] = array(); foreach($attachments as $a ) { $file = array('name' => $a['name'], 'type' => $a['type']); diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 9b1e669715223d8d9a0a48b9e3834ca4184c6685..6883cdaf6a7560437c4ee0fcc5a00886bf111004 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -163,9 +163,9 @@ class Mail_Parse { } /* static */ - function findHeaderEntry($headers, $name) { + function findHeaderEntry($headers, $name, $allEntries=false) { if (!is_array($headers)) - $headers = self::splitHeaders($headers); + $headers = self::splitHeaders($headers, $allEntries); foreach ($headers as $key=>$val) if (strcasecmp($key, $name) === 0) return $val; @@ -400,7 +400,6 @@ class Mail_Parse { 'data' => $at->Data, 'type' => @$at->AttachMimeTag ?: false, 'name' => $at->getName(), - 'encoding' => @$at->AttachEncoding ?: false, ); } return $files; diff --git a/include/class.ostsession.php b/include/class.ostsession.php index db51e89e771caaaff6fe9bdb1d3e2808b96e548c..beb344f9f3734f5e286e9d2e4aff0060d6406cb2 100644 --- a/include/class.ostsession.php +++ b/include/class.ostsession.php @@ -26,8 +26,12 @@ class osTicketSession { if(!$this->ttl) $this->ttl=SESSION_TTL; + // Set osTicket specific session name. session_name('OSTSESSID'); + // Forced cleanup on shutdown + register_shutdown_function('session_write_close'); + if (OsticketConfig::getDBVersion()) return session_start(); @@ -56,8 +60,6 @@ class osTicketSession { array(&$this, 'destroy'), array(&$this, 'gc') ); - //Forced cleanup. - register_shutdown_function('session_write_close'); //Start the session. session_start(); diff --git a/include/class.staff.php b/include/class.staff.php index 217b36c50c17babcaae390ba5ca492057790fd02..1334a785dcc88761e10e2c68bca1a3489d62e361 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -137,6 +137,10 @@ class Staff extends AuthenticatedUser { return $this->check_passwd($password, false); } + function hasPassword() { + return (bool) $this->ht['passwd']; + } + function forcePasswdRest() { return db_query('UPDATE '.STAFF_TABLE.' SET change_passwd=1 WHERE staff_id='.db_input($this->getId())); } @@ -862,6 +866,8 @@ class Staff extends AuthenticatedUser { if(isset($vars['change_passwd'])) $sql.=' ,change_passwd=1'; } + elseif (!isset($vars['change_passwd'])) + $sql .= ' ,change_passwd=0'; if($id) { $sql='UPDATE '.STAFF_TABLE.' '.$sql.' WHERE staff_id='.db_input($id); diff --git a/include/class.ticket.php b/include/class.ticket.php index 855d4650431164713b28c85ee2390e4482c7f258..df83644a8da74e58bda87435ab10701eb9adf1a2 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -2234,6 +2234,10 @@ class Ticket { # function if (isset($vars['autorespond'])) $autorespond=$vars['autorespond']; + # Apply filter-specific priority + if ($vars['priorityId']) + $form->setAnswer('priority', null, $vars['priorityId']); + // OK...just do it. $deptId=$vars['deptId']; //pre-selected Dept if any. $source=ucfirst($vars['source']); diff --git a/include/tnef_decoder.php b/include/tnef_decoder.php index f0eba4e792914621fefbbbdf4f2f1cd5f9c94e76..18e95d697c5eba8bb218ff81d5e9c903b2cedbd7 100644 --- a/include/tnef_decoder.php +++ b/include/tnef_decoder.php @@ -110,10 +110,13 @@ class TnefStreamReader implements Iterator { } function check($block) { - $sum = 0; - for ($i=0, $k=strlen($block['data']); $i < $k; $i++) - $sum += ord($block['data'][$i]); - if ($block['checksum'] != ($sum % 65536)) + $sum = 0; $bytes = strlen($block['data']); $bs = 1024; + for ($i=0; $i < $bytes; $i+=$bs) { + $b = unpack('C*', substr($block['data'], $i, min($bs, $bytes-$i))); + $sum += array_sum($b); + $sum = $sum % 65536; + } + if ($block['checksum'] != $sum) throw new TnefException('Corrupted block. Invalid checksum'); } diff --git a/scp/pwreset.php b/scp/pwreset.php index 6d749e2d5fe8c3b882bf2e0ffb1f012a046d3636..735765b05b0e780cfe7e0f704d72f748f2466ee8 100644 --- a/scp/pwreset.php +++ b/scp/pwreset.php @@ -36,7 +36,10 @@ if($_POST) { switch ($_POST['do']) { case 'sendmail': if (($staff=Staff::lookup($_POST['userid']))) { - if (!$staff->sendResetEmail()) { + if (!$staff->hasPassword()) { + $msg = 'Unable to reset password. Contact your administrator'; + } + elseif (!$staff->sendResetEmail()) { $tpl = 'pwreset.sent.php'; } }